]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge branch 'drm-radeon-kms' of git://git.kernel.org/pub/scm/linux/kernel/git/airlie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 29 Jul 2009 19:31:59 +0000 (12:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 29 Jul 2009 19:31:59 +0000 (12:31 -0700)
* 'drm-radeon-kms' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (35 commits)
  drm/radeon: set fb aperture sizes for framebuffer handoff.
  drm/ttm: fix highuser vs dma32 confusion.
  drm/radeon: Fix size used for benchmarking BO copies.
  drm/radeon: Add radeon.test parameter for running BO GPU copy tests.
  drm/radeon/kms: allow interruptible waits for objects.
  drm/ttm: powerpc: Fix Highmem cache flushing.
  x86: Export kmap_atomic_prot() needed for TTM.
  drm/ttm: Fix ttm in-kernel copying of pages with non-standard caching attributes.
  drm/ttm: Fix an oops and sync object leak.
  drm/radeon/kms: vram sizing on certain r100 chips needs workaround.
  drm/radeon: Pay more attention to object placement requested by userspace.
  drm/radeon: Fall back to evicting BOs with memcpy if necessary.
  drm/radeon: Don't unreserve twice on failure to validate.
  drm/radeon/kms: fix bandwidth computation on avivo hardware
  drm/radeon/kms: add initial colortiling support.
  drm/radeon/kms: fix hotspot handling on pre-avivo chips
  drm/radeon/kms: enable frac fb divs on rs600/rs690/rs740
  drm/radeon/kms: add PLL flag to prefer frequencies <= the target freq
  drm/radeon/kms: block RN50 from using 3D engine.
  drm/radeon/kms: fix VRAM sizing like DDX does it.
  ...

992 files changed:
CREDITS
Documentation/DocBook/mac80211.tmpl
Documentation/RCU/rculist_nulls.txt
Documentation/connector/cn_test.c
Documentation/connector/ucon.c
Documentation/driver-model/driver.txt
Documentation/exception.txt [deleted file]
Documentation/filesystems/sysfs.txt
Documentation/kernel-parameters.txt
Documentation/networking/6pack.txt
Documentation/scheduler/sched-rt-group.txt
Documentation/sound/alsa/Procfile.txt
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/gspca.txt
Documentation/x86/00-INDEX
Documentation/x86/exception-tables.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/include/asm/thread_info.h
arch/alpha/include/asm/tlb.h
arch/alpha/kernel/ptrace.c
arch/arm/configs/u300_defconfig
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlb.h
arch/arm/mach-ep93xx/dma-m2p.c
arch/arm/mach-kirkwood/mpp.h
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/armadillo5x0.c
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/pcm037.c
arch/arm/mach-mx3/pcm037.h [new file with mode: 0644]
arch/arm/mach-mx3/pcm037_eet.c [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/mfp-pxa300.h
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-realview/core.c
arch/arm/mach-u300/core.c
arch/arm/mach-versatile/core.c
arch/arm/plat-mxc/include/mach/iomux-mx3.h
arch/arm/plat-pxa/gpio.c
arch/avr32/include/asm/pgalloc.h
arch/avr32/include/asm/thread_info.h
arch/blackfin/include/asm/context.S
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/hardirq.h
arch/blackfin/include/asm/processor.h
arch/blackfin/include/asm/thread_info.h
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/cplb-nompu/cplbinit.c
arch/blackfin/kernel/process.c
arch/blackfin/kernel/ptrace.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/sys_bfin.c
arch/blackfin/kernel/traps.c
arch/blackfin/lib/lshrdi3.c
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/include/mach/anomaly.h
arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf538/include/mach/anomaly.h
arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf561/include/mach/mem_map.h
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/smp.c
arch/cris/include/asm/pgalloc.h
arch/cris/include/asm/thread_info.h
arch/cris/kernel/sys_cris.c
arch/frv/include/asm/pgalloc.h
arch/frv/include/asm/pgtable.h
arch/frv/include/asm/thread_info.h
arch/h8300/include/asm/thread_info.h
arch/ia64/include/asm/fpu.h
arch/ia64/include/asm/pgalloc.h
arch/ia64/include/asm/thread_info.h
arch/ia64/include/asm/tlb.h
arch/ia64/include/asm/xen/hypervisor.h
arch/ia64/kernel/dma-mapping.c
arch/ia64/kernel/ptrace.c
arch/m32r/include/asm/pgalloc.h
arch/m32r/include/asm/thread_info.h
arch/m32r/kernel/ptrace.c
arch/m68k/include/asm/motorola_pgalloc.h
arch/m68k/include/asm/sun3_pgalloc.h
arch/m68k/include/asm/thread_info_mm.h
arch/m68k/include/asm/thread_info_no.h
arch/microblaze/Makefile
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/prom.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/include/asm/tlb.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/kernel/Makefile
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/cpuinfo-static.c
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/module.c
arch/microblaze/kernel/ptrace.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/signal.c
arch/microblaze/kernel/sys_microblaze.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/mm/fault.c
arch/mips/include/asm/pgalloc.h
arch/mips/include/asm/thread_info.h
arch/mips/kernel/ptrace32.c
arch/mips/mm/hugetlbpage.c
arch/mn10300/include/asm/pgalloc.h
arch/mn10300/include/asm/thread_info.h
arch/mn10300/kernel/ptrace.c
arch/mn10300/kernel/signal.c
arch/mn10300/kernel/sys_mn10300.c
arch/mn10300/kernel/traps.c
arch/mn10300/kernel/vmlinux.lds.S
arch/mn10300/mm/fault.c
arch/mn10300/mm/misalignment.c
arch/parisc/include/asm/thread_info.h
arch/parisc/include/asm/tlb.h
arch/powerpc/include/asm/pgalloc-32.h
arch/powerpc/include/asm/pgalloc-64.h
arch/powerpc/include/asm/pgalloc.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/kernel/power7-pmu.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/vector.S
arch/powerpc/mm/hugetlbpage.c
arch/s390/Kconfig
arch/s390/include/asm/atomic.h
arch/s390/include/asm/perf_counter.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/tlb.h
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/ipl.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/smp.c
arch/s390/kernel/vdso64/clock_gettime.S
arch/s390/lib/Makefile
arch/s390/lib/delay.c
arch/s390/lib/ucmpdi2.c [new file with mode: 0644]
arch/s390/mm/fault.c
arch/s390/power/swsusp.c
arch/s390/power/swsusp_asm64.S
arch/sh/include/asm/pgalloc.h
arch/sh/include/asm/thread_info.h
arch/sh/include/asm/tlb.h
arch/sh/mm/tlb-sh3.c
arch/sparc/include/asm/pgalloc_32.h
arch/sparc/include/asm/thread_info_32.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/tlb_64.h
arch/sparc/kernel/ptrace_32.c
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/time_64.c
arch/sparc/kernel/traps_32.c
arch/sparc/kernel/vio.c
arch/um/include/asm/pgalloc.h
arch/um/include/asm/thread_info.h
arch/um/include/asm/tlb.h
arch/x86/include/asm/atomic_32.h
arch/x86/include/asm/atomic_64.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/lguest_hcall.h
arch/x86/include/asm/pgalloc.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/stacktrace.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_64.h
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/mfgpt_32.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/atomic64_32.c [new file with mode: 0644]
arch/x86/lib/usercopy_32.c
arch/x86/mm/fault.c
arch/x86/mm/pgtable.c
arch/x86/mm/srat_64.c
arch/x86/oprofile/nmi_int.c
arch/x86/pci/i386.c
arch/xtensa/include/asm/thread_info.h
arch/xtensa/include/asm/tlb.h
block/blk-sysfs.c
block/cfq-iosched.c
block/elevator.c
block/scsi_ioctl.c
drivers/ata/ahci.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_at91.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_pcmcia.c
drivers/ata/sata_mv.c
drivers/ata/sata_sil.c
drivers/base/devres.c
drivers/base/firmware_class.c
drivers/base/sys.c
drivers/block/DAC960.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/osdblk.c [new file with mode: 0644]
drivers/block/pktcdvd.c
drivers/block/virtio_blk.c
drivers/block/z2ram.c
drivers/bluetooth/hci_vhci.c
drivers/char/amiserial.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/hvc_console.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_hdlc.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/nozomi.c
drivers/char/pcmcia/ipwireless/tty.c
drivers/char/pty.c
drivers/char/rio/rio_linux.c
drivers/char/riscom8.c
drivers/char/rocket.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/sx.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tpm/tpm.c
drivers/char/tty_buffer.c
drivers/char/tty_ioctl.c
drivers/char/tty_ldisc.c
drivers/char/tty_port.c
drivers/char/vc_screen.c
drivers/char/vr41xx_giu.c [deleted file]
drivers/char/vt.c
drivers/char/vt_ioctl.c
drivers/connector/cn_queue.c
drivers/connector/connector.c
drivers/cpufreq/cpufreq.c
drivers/edac/amd64_edac.c
drivers/gpio/vr41xx_giu.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_debugfs.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_i2c.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo_regs.h
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/via/via_irq.c
drivers/hid/hid-core.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/abituguru3.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/max6650.c
drivers/hwmon/sht15.c
drivers/hwmon/smsc47m1.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/chips/tsl2550.c
drivers/ide/ide-disk.c
drivers/ide/ide-tape.c
drivers/input/evdev.c
drivers/input/joydev.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/atkbd.c
drivers/input/misc/pcspkr.c
drivers/input/misc/wistron_btns.c
drivers/isdn/gigaset/interface.c
drivers/isdn/hisax/hfc_usb.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/mISDN/l1oip_core.c
drivers/isdn/mISDN/stack.c
drivers/lguest/lg.h
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-linear.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-si470x.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/dabusb.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/sn9c20x.c [new file with mode: 0644]
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/mt9v011.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc.h
drivers/media/video/s2255drv.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/se401.c
drivers/media/video/stk-webcam.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/v4l2-dev.c
drivers/media/video/zoran/zoran_driver.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/grukservices.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/pxamci.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi-media.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/8139too.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/arm/Kconfig
drivers/net/arm/Makefile
drivers/net/arm/at91_ether.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/arm/w90p910_ether.c [new file with mode: 0644]
drivers/net/at1700.c
drivers/net/atl1c/atl1c.h
drivers/net/atl1c/atl1c_main.c
drivers/net/atlx/atl2.c
drivers/net/benet/be_main.c
drivers/net/bmac.c
drivers/net/bnx2x_link.c
drivers/net/bonding/bond_main.c
drivers/net/can/dev.c
drivers/net/can/sja1000/sja1000.c
drivers/net/cnic.c
drivers/net/cs89x0.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/davinci_emac.c
drivers/net/e100.c
drivers/net/eepro.c
drivers/net/ehea/ehea_main.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/hamradio/6pack.c
drivers/net/ibm_newemac/rgmii.c
drivers/net/igb/e1000_82575.c
drivers/net/igb/igb_main.c
drivers/net/irda/irtty-sir.c
drivers/net/isa-skeleton.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/jazzsonic.c
drivers/net/ks8851.c [new file with mode: 0644]
drivers/net/ks8851.h [new file with mode: 0644]
drivers/net/macsonic.c
drivers/net/mlx4/cmd.c
drivers/net/mlx4/en_ethtool.c
drivers/net/mlx4/main.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ctx.c
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/phy_device.c
drivers/net/plip.c
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/ps3_gelic_net.c
drivers/net/ps3_gelic_wireless.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/sc92031.c
drivers/net/skge.c
drivers/net/sky2.c
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/net/smsc911x.c
drivers/net/sunvnet.c
drivers/net/tokenring/ibmtr.c
drivers/net/ucc_geth.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/cdc-phonet.c [new file with mode: 0644]
drivers/net/usb/cdc_eem.c
drivers/net/usb/kaweth.c
drivers/net/usb/pegasus.c
drivers/net/via-rhine.c
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/Kconfig
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/defs.h
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rtl818x/rtl8187_leds.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/of/of_mdio.c
drivers/oprofile/oprofile_stats.c
drivers/pci/hotplug/cpci_hotplug_core.c
drivers/pci/hotplug/cpqphp_ctrl.c
drivers/pci/hotplug/cpqphp_sysfs.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/syscall.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/hp-wmi.c
drivers/power/wm97xx_battery.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/monreader.c
drivers/s390/char/sclp_rw.h
drivers/s390/char/vmwatchdog.c
drivers/s390/crypto/ap_bus.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/sg.c
drivers/serial/bfin_sport_uart.c
drivers/serial/msm_serial.c
drivers/ssb/pcmcia.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/android/lowmemorykiller.c
drivers/staging/comedi/drivers/jr3_pci.c
drivers/staging/comedi/drivers/s626.c
drivers/staging/go7007/s2250-loader.c
drivers/staging/meilhaus/TODO
drivers/staging/rspiusb/rspiusb.c
drivers/staging/rt2870/rt2870.h
drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
drivers/staging/rtl8192su/Kconfig
drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c
drivers/staging/rtl8192su/r8192U_core.c
drivers/staging/rtl8192su/r8192U_pm.c
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/staging/stlc45xx/stlc45xx.c
drivers/staging/uc2322/Kconfig [deleted file]
drivers/staging/uc2322/Makefile [deleted file]
drivers/staging/uc2322/TODO [deleted file]
drivers/staging/uc2322/aten2011.c [deleted file]
drivers/staging/udlfb/udlfb.c
drivers/staging/usbip/usbip_common.c
drivers/staging/vt6655/device_main.c
drivers/telephony/ixj.c
drivers/telephony/phonedev.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usbtmc.c
drivers/usb/core/Kconfig
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/core/message.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/audio.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/fhci-sched.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-hcd.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/misc/Kconfig
drivers/usb/misc/iowarrior.c
drivers/usb/misc/rio500.c
drivers/usb/misc/usblcd.c
drivers/usb/musb/cppi_dma.h
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_regs.h
drivers/usb/otg/Kconfig
drivers/usb/otg/Makefile
drivers/usb/otg/langwell_otg.c [deleted file]
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/generic.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/sierra.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/option_ms.c
drivers/usb/storage/transport.c
drivers/video/Kconfig
drivers/video/atmel_lcdfb.c
drivers/video/backlight/pwm_bl.c
drivers/video/fbmem.c
drivers/video/fbmon.c
drivers/video/fsl-diu-fb.c
drivers/video/mx3fb.c
drivers/video/omap/omapfb_main.c
drivers/video/sm501fb.c
drivers/virtio/virtio_pci.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/w83697ug_wdt.c
fs/9p/vfs_addr.c
fs/Kconfig
fs/adfs/super.c
fs/afs/dir.c
fs/afs/super.c
fs/autofs4/dev-ioctl.c
fs/bfs/dir.c
fs/bfs/file.c
fs/bio.c
fs/btrfs/async-thread.c
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/print-tree.c
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/char_dev.c
fs/cifs/CHANGES
fs/cifs/cifs_debug.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/compat.c
fs/compat_ioctl.c
fs/dlm/lock.c
fs/dlm/lowcomms.c
fs/dlm/plock.c
fs/ecryptfs/keystore.c
fs/exofs/common.h
fs/exofs/dir.c
fs/exofs/exofs.h
fs/exofs/file.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/exofs/osd.c
fs/exofs/super.c
fs/exofs/symlink.c
fs/ext2/ioctl.c
fs/ext3/dir.c
fs/ext3/inode.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/fat/dir.c
fs/fat/file.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fcntl.c
fs/freevxfs/vxfs_super.c
fs/fuse/dev.c
fs/gfs2/trace_gfs2.h
fs/hfs/super.c
fs/hfsplus/super.c
fs/hpfs/dir.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/inode.c
fs/hpfs/namei.c
fs/isofs/inode.c
fs/jbd/journal.c
fs/jbd/transaction.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/jffs2/super.c
fs/jfs/acl.c
fs/lockd/clntproc.c
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/nilfs2/Kconfig [new file with mode: 0644]
fs/nilfs2/bmap.c
fs/nilfs2/cpfile.c
fs/nilfs2/dat.c
fs/nilfs2/dir.c
fs/nilfs2/segment.c
fs/notify/Kconfig
fs/notify/dnotify/Kconfig
fs/notify/fsnotify.c
fs/notify/inotify/Kconfig
fs/notify/inotify/inotify_user.c
fs/notify/notification.c
fs/ocfs2/ioctl.c
fs/partitions/check.c
fs/pipe.c
fs/reiserfs/journal.c
fs/reiserfs/xattr.c
fs/squashfs/super.c
fs/sysfs/dir.c
fs/ubifs/io.c
fs/ubifs/ioctl.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/scan.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_file.c
include/asm-generic/4level-fixup.h
include/asm-generic/pgtable-nopmd.h
include/asm-generic/pgtable-nopud.h
include/asm-generic/tlb.h
include/asm-generic/vmlinux.lds.h
include/drm/drm_pciids.h
include/linux/backing-dev.h
include/linux/blkdev.h
include/linux/clockchips.h
include/linux/console_struct.h
include/linux/crash_dump.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/ext3_fs.h
include/linux/fsnotify_backend.h
include/linux/hardirq.h
include/linux/hrtimer.h
include/linux/interrupt.h
include/linux/kmemleak.h
include/linux/lguest.h
include/linux/libata.h
include/linux/of_mdio.h
include/linux/perf_counter.h
include/linux/personality.h
include/linux/quotaops.h
include/linux/rfkill.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/slub_def.h
include/linux/spinlock.h
include/linux/sunrpc/xdr.h
include/linux/syscalls.h
include/linux/tty.h
include/linux/usb.h
include/linux/usb/langwell_otg.h [deleted file]
include/linux/usb/serial.h
include/linux/videodev2.h
include/linux/virtio_net.h
include/media/v4l2-chip-ident.h
include/net/rose.h
include/net/sock.h
include/net/tcp.h
include/trace/events/block.h
include/trace/events/ext4.h
include/trace/events/irq.h
include/trace/events/jbd2.h
include/trace/events/kmem.h
include/trace/events/lockdep.h
include/trace/events/sched.h
include/trace/events/skb.h
include/trace/events/workqueue.h
init/Kconfig
kernel/fork.c
kernel/freezer.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/migration.c
kernel/kprobes.c
kernel/kthread.c
kernel/module.c
kernel/perf_counter.c
kernel/pid.c
kernel/power/user.c
kernel/rcutree.c
kernel/sched.c
kernel/sched_fair.c
kernel/sched_rt.c
kernel/softirq.c
kernel/time/clockevents.c
kernel/time/clocksource.c
kernel/timer.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_event_types.h
kernel/trace/trace_functions.c
kernel/trace/trace_output.c
kernel/trace/trace_stack.c
lib/dma-debug.c
lib/dynamic_debug.c
mm/backing-dev.c
mm/bootmem.c
mm/kmemleak.c
mm/memcontrol.c
mm/memory.c
mm/page-writeback.c
mm/page_alloc.c
mm/slub.c
mm/vmscan.c
net/9p/client.c
net/appletalk/ddp.c
net/atm/common.c
net/bridge/br_if.c
net/can/bcm.c
net/can/raw.c
net/core/datagram.c
net/core/netpoll.c
net/core/sock.c
net/dccp/output.c
net/dccp/proto.c
net/ipv4/fib_trie.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv6/ip6_output.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipx/af_ipx.c
net/irda/af_irda.c
net/irda/irnet/irnet.h
net/irda/irnet/irnet_ppp.c
net/irda/irttp.c
net/iucv/af_iucv.c
net/mac80211/Kconfig
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/rc80211_minstrel.c
net/mac80211/tx.c
net/netfilter/nf_conntrack_core.c
net/netfilter/xt_osf.c
net/rfkill/core.c
net/rose/af_rose.c
net/rose/rose_route.c
net/rxrpc/af_rxrpc.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/svc_xprt.c
net/unix/af_unix.c
net/wanrouter/wanmain.c
net/wireless/nl80211.c
net/wireless/scan.c
net/x25/af_x25.c
samples/trace_events/trace-events-sample.h
scripts/kconfig/lxdialog/util.c
scripts/kconfig/mconf.c
scripts/package/builddeb
sound/arm/pxa2xx-pcm-lib.c
sound/core/pcm_lib.c
sound/core/seq/Makefile
sound/isa/gus/gus_pcm.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ctxfi/ctamixer.c
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/ctsrc.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/riptide/riptide.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8988.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/usb/Kconfig
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/usbaudio.c
sound/usb/usbmixer.c
tools/perf/Documentation/perf-report.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-help.c
tools/perf/builtin-list.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/perf.c
tools/perf/perf.h
tools/perf/util/alias.c
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/color.c
tools/perf/util/color.h
tools/perf/util/config.c
tools/perf/util/exec_cmd.c
tools/perf/util/header.h
tools/perf/util/help.c
tools/perf/util/help.h
tools/perf/util/include/asm/system.h [new file with mode: 0644]
tools/perf/util/include/linux/kernel.h [new file with mode: 0644]
tools/perf/util/include/linux/list.h [new file with mode: 0644]
tools/perf/util/include/linux/module.h [new file with mode: 0644]
tools/perf/util/include/linux/poison.h [new file with mode: 0644]
tools/perf/util/include/linux/prefetch.h [new file with mode: 0644]
tools/perf/util/include/linux/rbtree.h [new file with mode: 0644]
tools/perf/util/list.h [deleted file]
tools/perf/util/module.c [new file with mode: 0644]
tools/perf/util/module.h [new file with mode: 0644]
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-options.c
tools/perf/util/parse-options.h
tools/perf/util/quote.c
tools/perf/util/quote.h
tools/perf/util/rbtree.c [deleted file]
tools/perf/util/rbtree.h [deleted file]
tools/perf/util/strbuf.c
tools/perf/util/strbuf.h
tools/perf/util/string.h
tools/perf/util/strlist.c
tools/perf/util/strlist.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/util.h
tools/perf/util/wrapper.c

diff --git a/CREDITS b/CREDITS
index 2b88fb37ad503e12ed271aa26b1068b7c5d93aea..e76d300e9fe4d79b95c5993c566f024d68957a15 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1856,7 +1856,7 @@ E: rfkoenig@immd4.informatik.uni-erlangen.de
 D: The Linux Support Team Erlangen
 
 N: Andreas Koensgen
-E: ajk@iehk.rwth-aachen.de
+E: ajk@comnets.uni-bremen.de
 D: 6pack driver for AX.25
 
 N: Harald Koerfgen
index e36986663570d6be1577365645c25b11e866c138..f3f37f141dbdb4a00ab621e07a9c1fa361a1f782 100644 (file)
@@ -184,8 +184,6 @@ usage should require reading the full document.
 !Finclude/net/mac80211.h ieee80211_ctstoself_get
 !Finclude/net/mac80211.h ieee80211_ctstoself_duration
 !Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
-!Finclude/net/mac80211.h ieee80211_hdrlen
 !Finclude/net/mac80211.h ieee80211_wake_queue
 !Finclude/net/mac80211.h ieee80211_stop_queue
 !Finclude/net/mac80211.h ieee80211_wake_queues
index 93cb28d05dcd92da30dde47ec58205e2b0851022..18f9651ff23d411e96737ec070d4fc6bc29c50fe 100644 (file)
@@ -83,11 +83,12 @@ not detect it missed following items in original chain.
 obj = kmem_cache_alloc(...);
 lock_chain(); // typically a spin_lock()
 obj->key = key;
-atomic_inc(&obj->refcnt);
 /*
  * we need to make sure obj->key is updated before obj->next
+ * or obj->refcnt
  */
 smp_wmb();
+atomic_set(&obj->refcnt, 1);
 hlist_add_head_rcu(&obj->obj_node, list);
 unlock_chain(); // typically a spin_unlock()
 
@@ -159,6 +160,10 @@ out:
 obj = kmem_cache_alloc(cachep);
 lock_chain(); // typically a spin_lock()
 obj->key = key;
+/*
+ * changes to obj->key must be visible before refcnt one
+ */
+smp_wmb();
 atomic_set(&obj->refcnt, 1);
 /*
  * insert obj in RCU way (readers might be traversing chain)
index f688eba8770488e4ebf4fa147e5f6b643be10634..6a5be5d5c8e4895c9f30c8494066eca302ffa056 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     cn_test.c
  * 
- * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
  * All rights reserved.
  * 
  * This program is free software; you can redistribute it and/or modify
@@ -194,5 +194,5 @@ module_init(cn_test_init);
 module_exit(cn_test_fini);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Connector's test module");
index d738cde2a8d51603e7faa207d7aea014ebb80d48..c5092ad0ce4b24912dc361a59dc596ed9ccda011 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     ucon.c
  *
- * Copyright (c) 2004+ Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net>
  *
  *
  * This program is free software; you can redistribute it and/or modify
index 82132169d47a837fc55ea9d53555abc29b2c7b5d..60120fb3b9618181a9e58f855cdef3ecdc5d0649 100644 (file)
@@ -207,8 +207,8 @@ Attributes
 ~~~~~~~~~~
 struct driver_attribute {
         struct attribute        attr;
-        ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off);
-        ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off);
+        ssize_t (*show)(struct device_driver *driver, char *buf);
+        ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
 };
 
 Device drivers can export attributes via their sysfs directories. 
diff --git a/Documentation/exception.txt b/Documentation/exception.txt
deleted file mode 100644 (file)
index 2d5aded..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-     Kernel level exception handling in Linux 2.1.8
-  Commentary by Joerg Pommnitz <joerg@raleigh.ibm.com>
-
-When a process runs in kernel mode, it often has to access user 
-mode memory whose address has been passed by an untrusted program. 
-To protect itself the kernel has to verify this address.
-
-In older versions of Linux this was done with the 
-int verify_area(int type, const void * addr, unsigned long size) 
-function (which has since been replaced by access_ok()).
-
-This function verified that the memory area starting at address 
-'addr' and of size 'size' was accessible for the operation specified
-in type (read or write). To do this, verify_read had to look up the 
-virtual memory area (vma) that contained the address addr. In the 
-normal case (correctly working program), this test was successful. 
-It only failed for a few buggy programs. In some kernel profiling
-tests, this normally unneeded verification used up a considerable
-amount of time.
-
-To overcome this situation, Linus decided to let the virtual memory 
-hardware present in every Linux-capable CPU handle this test.
-
-How does this work?
-
-Whenever the kernel tries to access an address that is currently not 
-accessible, the CPU generates a page fault exception and calls the 
-page fault handler 
-
-void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-
-in arch/i386/mm/fault.c. The parameters on the stack are set up by 
-the low level assembly glue in arch/i386/kernel/entry.S. The parameter
-regs is a pointer to the saved registers on the stack, error_code 
-contains a reason code for the exception.
-
-do_page_fault first obtains the unaccessible address from the CPU 
-control register CR2. If the address is within the virtual address 
-space of the process, the fault probably occurred, because the page 
-was not swapped in, write protected or something similar. However, 
-we are interested in the other case: the address is not valid, there 
-is no vma that contains this address. In this case, the kernel jumps 
-to the bad_area label. 
-
-There it uses the address of the instruction that caused the exception 
-(i.e. regs->eip) to find an address where the execution can continue 
-(fixup). If this search is successful, the fault handler modifies the 
-return address (again regs->eip) and returns. The execution will 
-continue at the address in fixup.
-
-Where does fixup point to?
-
-Since we jump to the contents of fixup, fixup obviously points 
-to executable code. This code is hidden inside the user access macros. 
-I have picked the get_user macro defined in include/asm/uaccess.h as an
-example. The definition is somewhat hard to follow, so let's peek at 
-the code generated by the preprocessor and the compiler. I selected
-the get_user call in drivers/char/console.c for a detailed examination.
-
-The original code in console.c line 1405:
-        get_user(c, buf);
-
-The preprocessor output (edited to become somewhat readable):
-
-(
-  {        
-    long __gu_err = - 14 , __gu_val = 0;        
-    const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));        
-    if (((((0 + current_set[0])->tss.segment) == 0x18 )  || 
-       (((sizeof(*(buf))) <= 0xC0000000UL) && 
-       ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))        
-      do {
-        __gu_err  = 0;        
-        switch ((sizeof(*(buf)))) {        
-          case 1: 
-            __asm__ __volatile__(        
-              "1:      mov" "b" " %2,%" "b" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "b" " %" "b" "1,%" "b" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        
-              "        .long 1b,3b\n"        
-              ".text"        : "=r"(__gu_err), "=q" (__gu_val): "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ; 
-              break;        
-          case 2: 
-            __asm__ __volatile__(
-              "1:      mov" "w" " %2,%" "w" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "w" " %" "w" "1,%" "w" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        
-              "        .long 1b,3b\n"        
-              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )); 
-              break;        
-          case 4: 
-            __asm__ __volatile__(        
-              "1:      mov" "l" " %2,%" "" "1\n"        
-              "2:\n"        
-              ".section .fixup,\"ax\"\n"        
-              "3:      movl %3,%0\n"        
-              "        xor" "l" " %" "" "1,%" "" "1\n"        
-              "        jmp 2b\n"        
-              ".section __ex_table,\"a\"\n"        
-              "        .align 4\n"        "        .long 1b,3b\n"        
-              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err)); 
-              break;        
-          default: 
-            (__gu_val) = __get_user_bad();        
-        }        
-      } while (0) ;        
-    ((c)) = (__typeof__(*((buf))))__gu_val;        
-    __gu_err;
-  }
-);
-
-WOW! Black GCC/assembly magic. This is impossible to follow, so let's
-see what code gcc generates:
-
- >         xorl %edx,%edx
- >         movl current_set,%eax
- >         cmpl $24,788(%eax)        
- >         je .L1424        
- >         cmpl $-1073741825,64(%esp)
- >         ja .L1423                
- > .L1424:
- >         movl %edx,%eax                        
- >         movl 64(%esp),%ebx
- > #APP
- > 1:      movb (%ebx),%dl                /* this is the actual user access */
- > 2:
- > .section .fixup,"ax"
- > 3:      movl $-14,%eax
- >         xorb %dl,%dl
- >         jmp 2b
- > .section __ex_table,"a"
- >         .align 4
- >         .long 1b,3b
- > .text
- > #NO_APP
- > .L1423:
- >         movzbl %dl,%esi
-
-The optimizer does a good job and gives us something we can actually 
-understand. Can we? The actual user access is quite obvious. Thanks 
-to the unified address space we can just access the address in user 
-memory. But what does the .section stuff do?????
-
-To understand this we have to look at the final kernel:
-
- > objdump --section-headers vmlinux
- > 
- > vmlinux:     file format elf32-i386
- > 
- > Sections:
- > Idx Name          Size      VMA       LMA       File off  Algn
- >   0 .text         00098f40  c0100000  c0100000  00001000  2**4
- >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
- >   1 .fixup        000016bc  c0198f40  c0198f40  00099f40  2**0
- >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
- >   2 .rodata       0000f127  c019a5fc  c019a5fc  0009b5fc  2**2
- >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
- >   3 __ex_table    000015c0  c01a9724  c01a9724  000aa724  2**2
- >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
- >   4 .data         0000ea58  c01abcf0  c01abcf0  000abcf0  2**4
- >                   CONTENTS, ALLOC, LOAD, DATA
- >   5 .bss          00018e21  c01ba748  c01ba748  000ba748  2**2
- >                   ALLOC
- >   6 .comment      00000ec4  00000000  00000000  000ba748  2**0
- >                   CONTENTS, READONLY
- >   7 .note         00001068  00000ec4  00000ec4  000bb60c  2**0
- >                   CONTENTS, READONLY
-
-There are obviously 2 non standard ELF sections in the generated object
-file. But first we want to find out what happened to our code in the
-final kernel executable:
-
- > objdump --disassemble --section=.text vmlinux
- >
- > c017e785 <do_con_write+c1> xorl   %edx,%edx
- > c017e787 <do_con_write+c3> movl   0xc01c7bec,%eax
- > c017e78c <do_con_write+c8> cmpl   $0x18,0x314(%eax)
- > c017e793 <do_con_write+cf> je     c017e79f <do_con_write+db>
- > c017e795 <do_con_write+d1> cmpl   $0xbfffffff,0x40(%esp,1)
- > c017e79d <do_con_write+d9> ja     c017e7a7 <do_con_write+e3>
- > c017e79f <do_con_write+db> movl   %edx,%eax
- > c017e7a1 <do_con_write+dd> movl   0x40(%esp,1),%ebx
- > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
- > c017e7a7 <do_con_write+e3> movzbl %dl,%esi
-
-The whole user memory access is reduced to 10 x86 machine instructions.
-The instructions bracketed in the .section directives are no longer
-in the normal execution path. They are located in a different section 
-of the executable file:
-
- > objdump --disassemble --section=.fixup vmlinux
- > 
- > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
- > c0199ffa <.fixup+10ba> xorb   %dl,%dl
- > c0199ffc <.fixup+10bc> jmp    c017e7a7 <do_con_write+e3>
-
-And finally:
- > objdump --full-contents --section=__ex_table vmlinux
- > 
- >  c01aa7c4 93c017c0 e09f19c0 97c017c0 99c017c0  ................
- >  c01aa7d4 f6c217c0 e99f19c0 a5e717c0 f59f19c0  ................
- >  c01aa7e4 080a18c0 01a019c0 0a0a18c0 04a019c0  ................
-
-or in human readable byte order:
-
- >  c01aa7c4 c017c093 c0199fe0 c017c097 c017c099  ................
- >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
-                               ^^^^^^^^^^^^^^^^^
-                               this is the interesting part!
- >  c01aa7e4 c0180a08 c019a001 c0180a0a c019a004  ................
-
-What happened? The assembly directives
-
-.section .fixup,"ax"
-.section __ex_table,"a"
-
-told the assembler to move the following code to the specified
-sections in the ELF object file. So the instructions
-3:      movl $-14,%eax
-        xorb %dl,%dl
-        jmp 2b
-ended up in the .fixup section of the object file and the addresses
-        .long 1b,3b
-ended up in the __ex_table section of the object file. 1b and 3b
-are local labels. The local label 1b (1b stands for next label 1 
-backward) is the address of the instruction that might fault, i.e. 
-in our case the address of the label 1 is c017e7a5:
-the original assembly code: > 1:      movb (%ebx),%dl
-and linked in vmlinux     : > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
-
-The local label 3 (backwards again) is the address of the code to handle
-the fault, in our case the actual value is c0199ff5:
-the original assembly code: > 3:      movl $-14,%eax
-and linked in vmlinux     : > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
-
-The assembly code
- > .section __ex_table,"a"
- >         .align 4
- >         .long 1b,3b
-
-becomes the value pair
- >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
-                               ^this is ^this is
-                               1b       3b 
-c017e7a5,c0199ff5 in the exception table of the kernel.
-
-So, what actually happens if a fault from kernel mode with no suitable
-vma occurs?
-
-1.) access to invalid address:
- > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
-2.) MMU generates exception
-3.) CPU calls do_page_fault
-4.) do page fault calls search_exception_table (regs->eip == c017e7a5);
-5.) search_exception_table looks up the address c017e7a5 in the
-    exception table (i.e. the contents of the ELF section __ex_table) 
-    and returns the address of the associated fault handle code c0199ff5.
-6.) do_page_fault modifies its own return address to point to the fault 
-    handle code and returns.
-7.) execution continues in the fault handling code.
-8.) 8a) EAX becomes -EFAULT (== -14)
-    8b) DL  becomes zero (the value we "read" from user space)
-    8c) execution continues at local label 2 (address of the
-        instruction immediately after the faulting user access).
-
-The steps 8a to 8c in a certain way emulate the faulting instruction.
-
-That's it, mostly. If you look at our example, you might ask why
-we set EAX to -EFAULT in the exception handler code. Well, the
-get_user macro actually returns a value: 0, if the user access was
-successful, -EFAULT on failure. Our original code did not test this
-return value, however the inline assembly code in get_user tries to
-return -EFAULT. GCC selected EAX to return this value.
-
-NOTE:
-Due to the way that the exception table is built and needs to be ordered,
-only use exceptions for code in the .text section.  Any other section
-will cause the exception table to not be sorted correctly, and the
-exceptions will fail.
index 7e81e37c0b1ec0ccbea30a92ffbf70f495ffdbd0..b245d524d5682afe30a194821ab62e619092ff3c 100644 (file)
@@ -23,7 +23,8 @@ interface.
 Using sysfs
 ~~~~~~~~~~~
 
-sysfs is always compiled in. You can access it by doing:
+sysfs is always compiled in if CONFIG_SYSFS is defined. You can access
+it by doing:
 
     mount -t sysfs sysfs /sys 
 
index d77fbd8b79acd4f985dd3c6a9ef6424d7af76b96..dd1a6d4bb7473c4966a720c40e8af0492f9853c5 100644 (file)
@@ -1720,8 +1720,8 @@ and is between 256 and 4096 characters. It is defined in the file
        oprofile.cpu_type=      Force an oprofile cpu type
                        This might be useful if you have an older oprofile
                        userland or if you want common events.
-                       Format: { archperfmon }
-                       archperfmon: [X86] Force use of architectural
+                       Format: { arch_perfmon }
+                       arch_perfmon: [X86] Force use of architectural
                                perfmon on Intel CPUs instead of the
                                CPU specific event set.
 
index d0777a1200e1a3a3c224db65cac7fe0d866ea44f..8f339428fdf441d40bb653a226dc12fe9baea928 100644 (file)
@@ -1,7 +1,7 @@
 This is the 6pack-mini-HOWTO, written by
 
 Andreas Könsgen DG3KQ
-Internet: ajk@iehk.rwth-aachen.de
+Internet: ajk@comnets.uni-bremen.de
 AMPR-net: dg3kq@db0pra.ampr.org
 AX.25:    dg3kq@db0ach.#nrw.deu.eu
 
index 1df7f9cdab0576227671703c6fec1fc780ec596b..86eabe6c3419fd4f26aba47a090ecc1caff9a1fd 100644 (file)
@@ -73,7 +73,7 @@ The remaining CPU time will be used for user input and other tasks. Because
 realtime tasks have explicitly allocated the CPU time they need to perform
 their tasks, buffer underruns in the graphics or audio can be eliminated.
 
-NOTE: the above example is not fully implemented as of yet (2.6.25). We still
+NOTE: the above example is not fully implemented yet. We still
 lack an EDF scheduler to make non-uniform periods usable.
 
 
@@ -140,14 +140,15 @@ The other option is:
 
 .o CONFIG_CGROUP_SCHED (aka "Basis for grouping tasks" = "Control groups")
 
-This uses the /cgroup virtual file system and "/cgroup/<cgroup>/cpu.rt_runtime_us"
-to control the CPU time reserved for each control group instead.
+This uses the /cgroup virtual file system and
+"/cgroup/<cgroup>/cpu.rt_runtime_us" to control the CPU time reserved for each
+control group instead.
 
 For more information on working with control groups, you should read
 Documentation/cgroups/cgroups.txt as well.
 
-Group settings are checked against the following limits in order to keep the configuration
-schedulable:
+Group settings are checked against the following limits in order to keep the
+configuration schedulable:
 
    \Sum_{i} runtime_{i} / global_period <= global_runtime / global_period
 
@@ -189,7 +190,7 @@ Implementing SCHED_EDF might take a while to complete. Priority Inheritance is
 the biggest challenge as the current linux PI infrastructure is geared towards
 the limited static priority levels 0-99. With deadline scheduling you need to
 do deadline inheritance (since priority is inversely proportional to the
-deadline delta (deadline - now).
+deadline delta (deadline - now)).
 
 This means the whole PI machinery will have to be reworked - and that is one of
 the most complex pieces of code we have.
index 381908d8ca4231dde74f5c138b200782036760c1..719a819f8cc2c0e597e27b2b8bcd7caa17638ea2 100644 (file)
@@ -101,6 +101,8 @@ card*/pcm*/xrun_debug
          bit 0 = Enable XRUN/jiffies debug messages
          bit 1 = Show stack trace at XRUN / jiffies check
          bit 2 = Enable additional jiffies check
+         bit 3 = Log hwptr update at each period interrupt
+         bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
 
        When the bit 0 is set, the driver will show the messages to
        kernel log when an xrun is detected.  The debug message is
@@ -117,6 +119,9 @@ card*/pcm*/xrun_debug
        buggy) hardware that doesn't give smooth pointer updates.
        This feature is enabled via the bit 2.
 
+       Bits 3 and 4 are for logging the hwptr records.  Note that
+       these will give flood of kernel messages.
+
 card*/pcm*/sub*/info
        The general information of this PCM sub-stream.
 
index 014d255231fc7cea3eb73378788e0ddae551eb88..68c236c018462e2e3d687e4a078c44815786db0d 100644 (file)
@@ -20,7 +20,7 @@
  19 -> EM2860/SAA711X Reference Design          (em2860)
  20 -> AMD ATI TV Wonder HD 600                 (em2880)        [0438:b002]
  21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800)        [eb1a:2801]
- 22 -> Unknown EM2750/EM2751 webcam grabber     (em2750)        [eb1a:2750,eb1a:2751]
+ 22 -> EM2710/EM2750/EM2751 webcam grabber      (em2750)        [eb1a:2750,eb1a:2751]
  23 -> Huaqi DLCW-130                           (em2750)
  24 -> D-Link DUB-T210 TV Tuner                 (em2820/em2840) [2001:f112]
  25 -> Gadmei UTV310                            (em2820/em2840)
index 2bcf78896e225a191cc58c23d8636ad92365ecd7..573f95b588079b6ae1ede70f479cf539e397e2eb 100644 (file)
@@ -44,7 +44,9 @@ zc3xx         0458:7007       Genius VideoCam V2
 zc3xx          0458:700c       Genius VideoCam V3
 zc3xx          0458:700f       Genius VideoCam Web V2
 sonixj         0458:7025       Genius Eye 311Q
+sn9c20x                0458:7029       Genius Look 320s
 sonixj         0458:702e       Genius Slim 310 NB
+sn9c20x                045e:00f4       LifeCam VX-6000 (SN9C20x + OV9650)
 sonixj         045e:00f5       MicroSoft VX3000
 sonixj         045e:00f7       MicroSoft VX1000
 ov519          045e:028c       Micro$oft xbox cam
@@ -282,6 +284,28 @@ sonixj             0c45:613a       Microdia Sonix PC Camera
 sonixj         0c45:613b       Surfer SN-206
 sonixj         0c45:613c       Sonix Pccam168
 sonixj         0c45:6143       Sonix Pccam168
+sn9c20x                0c45:6240       PC Camera (SN9C201 + MT9M001)
+sn9c20x                0c45:6242       PC Camera (SN9C201 + MT9M111)
+sn9c20x                0c45:6248       PC Camera (SN9C201 + OV9655)
+sn9c20x                0c45:624e       PC Camera (SN9C201 + SOI968)
+sn9c20x                0c45:624f       PC Camera (SN9C201 + OV9650)
+sn9c20x                0c45:6251       PC Camera (SN9C201 + OV9650)
+sn9c20x                0c45:6253       PC Camera (SN9C201 + OV9650)
+sn9c20x                0c45:6260       PC Camera (SN9C201 + OV7670)
+sn9c20x                0c45:6270       PC Camera (SN9C201 + MT9V011/MT9V111/MT9V112)
+sn9c20x                0c45:627b       PC Camera (SN9C201 + OV7660)
+sn9c20x                0c45:627c       PC Camera (SN9C201 + HV7131R)
+sn9c20x                0c45:627f       PC Camera (SN9C201 + OV9650)
+sn9c20x                0c45:6280       PC Camera (SN9C202 + MT9M001)
+sn9c20x                0c45:6282       PC Camera (SN9C202 + MT9M111)
+sn9c20x                0c45:6288       PC Camera (SN9C202 + OV9655)
+sn9c20x                0c45:628e       PC Camera (SN9C202 + SOI968)
+sn9c20x                0c45:628f       PC Camera (SN9C202 + OV9650)
+sn9c20x                0c45:62a0       PC Camera (SN9C202 + OV7670)
+sn9c20x                0c45:62b0       PC Camera (SN9C202 + MT9V011/MT9V111/MT9V112)
+sn9c20x                0c45:62b3       PC Camera (SN9C202 + OV9655)
+sn9c20x                0c45:62bb       PC Camera (SN9C202 + OV7660)
+sn9c20x                0c45:62bc       PC Camera (SN9C202 + HV7131R)
 sunplus                0d64:0303       Sunplus FashionCam DXG
 etoms          102c:6151       Qcam Sangha CIF
 etoms          102c:6251       Qcam xxxxxx VGA
@@ -290,6 +314,7 @@ spca561             10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
 ov534          1415:2000       Sony HD Eye for PS3 (SLEH 00201)
 pac207         145f:013a       Trust WB-1300N
+sn9c20x                145f:013d       Trust WB-3600R
 vc032x         15b8:6001       HP 2.0 Megapixel
 vc032x         15b8:6002       HP 2.0 Megapixel rz406aa
 spca501                1776:501c       Arowana 300K CMOS Camera
@@ -300,4 +325,11 @@ spca500            2899:012c       Toptro Industrial
 spca508                8086:0110       Intel Easy PC Camera
 spca500                8086:0630       Intel Pocket PC Camera
 spca506                99fa:8988       Grandtec V.cap
+sn9c20x                a168:0610       Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x                a168:0611       Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x                a168:0613       Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x                a168:0618       Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x                a168:0614       Dino-Lite Digital Microscope (SN9C201 + MT9M111)
+sn9c20x                a168:0615       Dino-Lite Digital Microscope (SN9C201 + MT9M111)
+sn9c20x                a168:0617       Dino-Lite Digital Microscope (SN9C201 + MT9M111)
 spca561                abcd:cdee       Petcam
index dbe3377754af5ab0d36c5665a3a118e02fc5621f..f37b46d348614be9fc5a0b54a8c303617e979d56 100644 (file)
@@ -2,3 +2,5 @@
        - this file
 mtrr.txt
        - how to use x86 Memory Type Range Registers to increase performance
+exception-tables.txt
+       - why and how Linux kernel uses exception tables on x86
diff --git a/Documentation/x86/exception-tables.txt b/Documentation/x86/exception-tables.txt
new file mode 100644 (file)
index 0000000..32901aa
--- /dev/null
@@ -0,0 +1,292 @@
+     Kernel level exception handling in Linux
+  Commentary by Joerg Pommnitz <joerg@raleigh.ibm.com>
+
+When a process runs in kernel mode, it often has to access user
+mode memory whose address has been passed by an untrusted program.
+To protect itself the kernel has to verify this address.
+
+In older versions of Linux this was done with the
+int verify_area(int type, const void * addr, unsigned long size)
+function (which has since been replaced by access_ok()).
+
+This function verified that the memory area starting at address
+'addr' and of size 'size' was accessible for the operation specified
+in type (read or write). To do this, verify_read had to look up the
+virtual memory area (vma) that contained the address addr. In the
+normal case (correctly working program), this test was successful.
+It only failed for a few buggy programs. In some kernel profiling
+tests, this normally unneeded verification used up a considerable
+amount of time.
+
+To overcome this situation, Linus decided to let the virtual memory
+hardware present in every Linux-capable CPU handle this test.
+
+How does this work?
+
+Whenever the kernel tries to access an address that is currently not
+accessible, the CPU generates a page fault exception and calls the
+page fault handler
+
+void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+
+in arch/x86/mm/fault.c. The parameters on the stack are set up by
+the low level assembly glue in arch/x86/kernel/entry_32.S. The parameter
+regs is a pointer to the saved registers on the stack, error_code
+contains a reason code for the exception.
+
+do_page_fault first obtains the unaccessible address from the CPU
+control register CR2. If the address is within the virtual address
+space of the process, the fault probably occurred, because the page
+was not swapped in, write protected or something similar. However,
+we are interested in the other case: the address is not valid, there
+is no vma that contains this address. In this case, the kernel jumps
+to the bad_area label.
+
+There it uses the address of the instruction that caused the exception
+(i.e. regs->eip) to find an address where the execution can continue
+(fixup). If this search is successful, the fault handler modifies the
+return address (again regs->eip) and returns. The execution will
+continue at the address in fixup.
+
+Where does fixup point to?
+
+Since we jump to the contents of fixup, fixup obviously points
+to executable code. This code is hidden inside the user access macros.
+I have picked the get_user macro defined in arch/x86/include/asm/uaccess.h
+as an example. The definition is somewhat hard to follow, so let's peek at
+the code generated by the preprocessor and the compiler. I selected
+the get_user call in drivers/char/sysrq.c for a detailed examination.
+
+The original code in sysrq.c line 587:
+        get_user(c, buf);
+
+The preprocessor output (edited to become somewhat readable):
+
+(
+  {
+    long __gu_err = - 14 , __gu_val = 0;
+    const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));
+    if (((((0 + current_set[0])->tss.segment) == 0x18 )  ||
+       (((sizeof(*(buf))) <= 0xC0000000UL) &&
+       ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))
+      do {
+        __gu_err  = 0;
+        switch ((sizeof(*(buf)))) {
+          case 1:
+            __asm__ __volatile__(
+              "1:      mov" "b" " %2,%" "b" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "b" " %" "b" "1,%" "b" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"
+              "        .long 1b,3b\n"
+              ".text"        : "=r"(__gu_err), "=q" (__gu_val): "m"((*(struct __large_struct *)
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ;
+              break;
+          case 2:
+            __asm__ __volatile__(
+              "1:      mov" "w" " %2,%" "w" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "w" " %" "w" "1,%" "w" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"
+              "        .long 1b,3b\n"
+              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  ));
+              break;
+          case 4:
+            __asm__ __volatile__(
+              "1:      mov" "l" " %2,%" "" "1\n"
+              "2:\n"
+              ".section .fixup,\"ax\"\n"
+              "3:      movl %3,%0\n"
+              "        xor" "l" " %" "" "1,%" "" "1\n"
+              "        jmp 2b\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"        "        .long 1b,3b\n"
+              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
+                            (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err));
+              break;
+          default:
+            (__gu_val) = __get_user_bad();
+        }
+      } while (0) ;
+    ((c)) = (__typeof__(*((buf))))__gu_val;
+    __gu_err;
+  }
+);
+
+WOW! Black GCC/assembly magic. This is impossible to follow, so let's
+see what code gcc generates:
+
+ >         xorl %edx,%edx
+ >         movl current_set,%eax
+ >         cmpl $24,788(%eax)
+ >         je .L1424
+ >         cmpl $-1073741825,64(%esp)
+ >         ja .L1423
+ > .L1424:
+ >         movl %edx,%eax
+ >         movl 64(%esp),%ebx
+ > #APP
+ > 1:      movb (%ebx),%dl                /* this is the actual user access */
+ > 2:
+ > .section .fixup,"ax"
+ > 3:      movl $-14,%eax
+ >         xorb %dl,%dl
+ >         jmp 2b
+ > .section __ex_table,"a"
+ >         .align 4
+ >         .long 1b,3b
+ > .text
+ > #NO_APP
+ > .L1423:
+ >         movzbl %dl,%esi
+
+The optimizer does a good job and gives us something we can actually
+understand. Can we? The actual user access is quite obvious. Thanks
+to the unified address space we can just access the address in user
+memory. But what does the .section stuff do?????
+
+To understand this we have to look at the final kernel:
+
+ > objdump --section-headers vmlinux
+ >
+ > vmlinux:     file format elf32-i386
+ >
+ > Sections:
+ > Idx Name          Size      VMA       LMA       File off  Algn
+ >   0 .text         00098f40  c0100000  c0100000  00001000  2**4
+ >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
+ >   1 .fixup        000016bc  c0198f40  c0198f40  00099f40  2**0
+ >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
+ >   2 .rodata       0000f127  c019a5fc  c019a5fc  0009b5fc  2**2
+ >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
+ >   3 __ex_table    000015c0  c01a9724  c01a9724  000aa724  2**2
+ >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
+ >   4 .data         0000ea58  c01abcf0  c01abcf0  000abcf0  2**4
+ >                   CONTENTS, ALLOC, LOAD, DATA
+ >   5 .bss          00018e21  c01ba748  c01ba748  000ba748  2**2
+ >                   ALLOC
+ >   6 .comment      00000ec4  00000000  00000000  000ba748  2**0
+ >                   CONTENTS, READONLY
+ >   7 .note         00001068  00000ec4  00000ec4  000bb60c  2**0
+ >                   CONTENTS, READONLY
+
+There are obviously 2 non standard ELF sections in the generated object
+file. But first we want to find out what happened to our code in the
+final kernel executable:
+
+ > objdump --disassemble --section=.text vmlinux
+ >
+ > c017e785 <do_con_write+c1> xorl   %edx,%edx
+ > c017e787 <do_con_write+c3> movl   0xc01c7bec,%eax
+ > c017e78c <do_con_write+c8> cmpl   $0x18,0x314(%eax)
+ > c017e793 <do_con_write+cf> je     c017e79f <do_con_write+db>
+ > c017e795 <do_con_write+d1> cmpl   $0xbfffffff,0x40(%esp,1)
+ > c017e79d <do_con_write+d9> ja     c017e7a7 <do_con_write+e3>
+ > c017e79f <do_con_write+db> movl   %edx,%eax
+ > c017e7a1 <do_con_write+dd> movl   0x40(%esp,1),%ebx
+ > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+ > c017e7a7 <do_con_write+e3> movzbl %dl,%esi
+
+The whole user memory access is reduced to 10 x86 machine instructions.
+The instructions bracketed in the .section directives are no longer
+in the normal execution path. They are located in a different section
+of the executable file:
+
+ > objdump --disassemble --section=.fixup vmlinux
+ >
+ > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
+ > c0199ffa <.fixup+10ba> xorb   %dl,%dl
+ > c0199ffc <.fixup+10bc> jmp    c017e7a7 <do_con_write+e3>
+
+And finally:
+ > objdump --full-contents --section=__ex_table vmlinux
+ >
+ >  c01aa7c4 93c017c0 e09f19c0 97c017c0 99c017c0  ................
+ >  c01aa7d4 f6c217c0 e99f19c0 a5e717c0 f59f19c0  ................
+ >  c01aa7e4 080a18c0 01a019c0 0a0a18c0 04a019c0  ................
+
+or in human readable byte order:
+
+ >  c01aa7c4 c017c093 c0199fe0 c017c097 c017c099  ................
+ >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
+                               ^^^^^^^^^^^^^^^^^
+                               this is the interesting part!
+ >  c01aa7e4 c0180a08 c019a001 c0180a0a c019a004  ................
+
+What happened? The assembly directives
+
+.section .fixup,"ax"
+.section __ex_table,"a"
+
+told the assembler to move the following code to the specified
+sections in the ELF object file. So the instructions
+3:      movl $-14,%eax
+        xorb %dl,%dl
+        jmp 2b
+ended up in the .fixup section of the object file and the addresses
+        .long 1b,3b
+ended up in the __ex_table section of the object file. 1b and 3b
+are local labels. The local label 1b (1b stands for next label 1
+backward) is the address of the instruction that might fault, i.e.
+in our case the address of the label 1 is c017e7a5:
+the original assembly code: > 1:      movb (%ebx),%dl
+and linked in vmlinux     : > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+
+The local label 3 (backwards again) is the address of the code to handle
+the fault, in our case the actual value is c0199ff5:
+the original assembly code: > 3:      movl $-14,%eax
+and linked in vmlinux     : > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
+
+The assembly code
+ > .section __ex_table,"a"
+ >         .align 4
+ >         .long 1b,3b
+
+becomes the value pair
+ >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
+                               ^this is ^this is
+                               1b       3b
+c017e7a5,c0199ff5 in the exception table of the kernel.
+
+So, what actually happens if a fault from kernel mode with no suitable
+vma occurs?
+
+1.) access to invalid address:
+ > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+2.) MMU generates exception
+3.) CPU calls do_page_fault
+4.) do page fault calls search_exception_table (regs->eip == c017e7a5);
+5.) search_exception_table looks up the address c017e7a5 in the
+    exception table (i.e. the contents of the ELF section __ex_table)
+    and returns the address of the associated fault handle code c0199ff5.
+6.) do_page_fault modifies its own return address to point to the fault
+    handle code and returns.
+7.) execution continues in the fault handling code.
+8.) 8a) EAX becomes -EFAULT (== -14)
+    8b) DL  becomes zero (the value we "read" from user space)
+    8c) execution continues at local label 2 (address of the
+        instruction immediately after the faulting user access).
+
+The steps 8a to 8c in a certain way emulate the faulting instruction.
+
+That's it, mostly. If you look at our example, you might ask why
+we set EAX to -EFAULT in the exception handler code. Well, the
+get_user macro actually returns a value: 0, if the user access was
+successful, -EFAULT on failure. Our original code did not test this
+return value, however the inline assembly code in get_user tries to
+return -EFAULT. GCC selected EAX to return this value.
+
+NOTE:
+Due to the way that the exception table is built and needs to be ordered,
+only use exceptions for code in the .text section.  Any other section
+will cause the exception table to not be sorted correctly, and the
+exceptions will fail.
index e4b1a3d596cc0528de759ee13e93cbd1bf02095e..ebc269152faf78f5136cb45432f29c39f8c67abe 100644 (file)
@@ -150,7 +150,7 @@ F:  drivers/scsi/53c700*
 
 6PACK NETWORK DRIVER FOR AX.25
 P:     Andreas Koensgen
-M:     ajk@iehk.rwth-aachen.de
+M:     ajk@comnets.uni-bremen.de
 L:     linux-hams@vger.kernel.org
 S:     Maintained
 F:     drivers/net/hamradio/6pack.c
@@ -1612,6 +1612,13 @@ S:       Supported
 F:     fs/configfs/
 F:     include/linux/configfs.h
 
+CONNECTOR
+P:     Evgeniy Polyakov
+M:     zbr@ioremap.net
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/connector/
+
 CONTROL GROUPS (CGROUPS)
 P:     Paul Menage
 M:     menage@google.com
@@ -3287,11 +3294,11 @@ F:      include/linux/ivtv*
 
 JFS FILESYSTEM
 P:     Dave Kleikamp
-M:     shaggy@austin.ibm.com
+M:     shaggy@linux.vnet.ibm.com
 L:     jfs-discussion@lists.sourceforge.net
 W:     http://jfs.sourceforge.net/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
-S:     Supported
+S:     Maintained
 F:     Documentation/filesystems/jfs.txt
 F:     fs/jfs/
 
@@ -4089,6 +4096,7 @@ L:        netfilter@vger.kernel.org
 L:     coreteam@netfilter.org
 W:     http://www.netfilter.org/
 W:     http://www.iptables.org/
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git
 S:     Supported
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
@@ -4407,7 +4415,7 @@ W:        http://www.nongnu.org/orinoco/
 S:     Maintained
 F:     drivers/net/wireless/orinoco/
 
-OSD LIBRARY
+OSD LIBRARY and FILESYSTEM
 P:     Boaz Harrosh
 M:     bharrosh@panasas.com
 P:     Benny Halevy
@@ -4416,6 +4424,9 @@ L:        osd-dev@open-osd.org
 W:     http://open-osd.org
 T:     git git://git.open-osd.org/open-osd.git
 S:     Maintained
+F:     drivers/scsi/osd/
+F:     drivers/include/scsi/osd_*
+F:     fs/exofs/
 
 P54 WIRELESS DRIVER
 P:     Michael Wu
@@ -5583,7 +5594,6 @@ S:        Odd Fixes
 F:     drivers/net/starfire*
 
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
-W:     http://mosquitonet.Stanford.EDU/strip.html
 S:     Orphan
 F:     drivers/net/wireless/strip.c
 F:     include/linux/if_strip.h
@@ -5851,7 +5861,7 @@ UBI FILE SYSTEM (UBIFS)
 P:     Artem Bityutskiy
 M:     dedekind@infradead.org
 P:     Adrian Hunter
-M:     ext-adrian.hunter@nokia.com
+M:     adrian.hunter@nokia.com
 L:     linux-mtd@lists.infradead.org
 T:     git git://git.infradead.org/ubifs-2.6.git
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
index 0aeec59c1f0a85f5b61c3fd6d61dceb8c9520dff..063d738405edbfe90b34de9335dab957b6362274 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 31
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc4
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
@@ -343,7 +343,8 @@ KBUILD_CPPFLAGS := -D__KERNEL__
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
                   -Werror-implicit-function-declaration \
-                  -Wno-format-security
+                  -Wno-format-security \
+                  -fno-delete-null-pointer-checks
 KBUILD_AFLAGS   := -D__ASSEMBLY__
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
@@ -565,7 +566,7 @@ KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
-KBUILD_CFLAGS  += $(call cc-option,-fwrapv)
+KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
 
 # revert to pre-gcc-4.4 behaviour of .eh_frame
 KBUILD_CFLAGS  += $(call cc-option,-fno-dwarf2-cfi-asm)
index d069526bd7673f9ead6eb33e825782ea690e2fb0..60c83abfde7027832e0e7609ac7e032accb66386 100644 (file)
@@ -37,6 +37,7 @@ struct thread_info {
        .task           = &tsk,                 \
        .exec_domain    = &default_exec_domain, \
        .addr_limit     = KERNEL_DS,            \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index c13636575fbab4fb14c17b75d53058b0f9181e1c..42866759f3fabd022c07c431a01bc9f45f6d91f4 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <asm-generic/tlb.h>
 
-#define __pte_free_tlb(tlb, pte)                       pte_free((tlb)->mm, pte)
-#define __pmd_free_tlb(tlb, pmd)                       pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte, address)              pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, address)              pmd_free((tlb)->mm, pmd)
  
 #endif
index 1e9ad52c460ec293aa70f9cbc5bb3094adc08d74..e072041d19f8ba97f15ee6922ee5955e4db36930 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 4762d900129841d637604195ecb8aaf4effcd218..7d61ae6e75daf7e9da06b214818ee0ad2ff22efa 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc1
-# Thu Jul  2 00:16:59 2009
+# Linux kernel version: 2.6.31-rc3
+# Thu Jul 16 23:36:10 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -9,7 +9,6 @@ CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-CONFIG_HAVE_TCM=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -113,7 +112,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-CONFIG_LBDAF=y
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -542,13 +541,14 @@ CONFIG_INPUT_EVDEV=y
 #
 CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_LM8323 is not set
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
@@ -911,7 +911,6 @@ CONFIG_REGULATOR=y
 # 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_BTRFS_FS is not set
 CONFIG_FILE_LOCKING=y
@@ -1122,7 +1121,6 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC32 is not set
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 4f8848260ee2b85b4256b9762aeb7ce68e29ef38..73394e50cbca26e4198349de503fd18554f331d6 100644 (file)
@@ -73,7 +73,7 @@ struct thread_info {
        .task           = &tsk,                                         \
        .exec_domain    = &default_exec_domain,                         \
        .flags          = 0,                                            \
-       .preempt_count  = 1,                                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,                           \
        .addr_limit     = KERNEL_DS,                                    \
        .cpu_domain     = domain_val(DOMAIN_USER, DOMAIN_MANAGER) |     \
                          domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |   \
index 321c83e43a1e7a2cc9d8d770417004a5c206be9a..f41a6f57cd1223aef8d00f450bc1b68365623b19 100644 (file)
@@ -102,8 +102,8 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 }
 
 #define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep)                pte_free((tlb)->mm, ptep)
-#define pmd_free_tlb(tlb, pmdp)                pmd_free((tlb)->mm, pmdp)
+#define pte_free_tlb(tlb, ptep, addr)  pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp, addr)  pmd_free((tlb)->mm, pmdp)
 
 #define tlb_migrate_finish(mm)         do { } while (0)
 
index a2df5bb7dff0d9cf799d8770e158dfc9885373e8..dbcac9c40a28883df558565be3c7e52c37426053 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
index e021a80c2cafa00df3cba91543a6e5dc55d05f7b..bc74278ed311c2bef402d6e16d808111669ed96e 100644 (file)
 
 #define MPP48_GPIO             MPP( 48, 0x0, 1, 1, 0,   0,   0,   1    )
 #define MPP48_TSMP12           MPP( 48, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP48_TDM_DTX          MPP( 48. 0x2, 0, 1, 0,   0,   0,   1    )
+#define MPP48_TDM_DTX          MPP( 48, 0x2, 0, 1, 0,   0,   0,   1    )
 
 #define MPP49_GPIO             MPP( 49, 0x0, 1, 1, 0,   0,   0,   1    )
 #define MPP49_TSMP9            MPP( 49, 0x1, 1, 1, 0,   0,   0,   1    )
index 17a21a291e2f6eb7d9bdb7593e76f2c2ecac2cc4..851f2458bf65f0d7443d02941f898d3c17e6494c 100644 (file)
@@ -36,6 +36,14 @@ config MACH_PCM037
          Include support for Phytec pcm037 platform. This includes
          specific configurations for the board and its peripherals.
 
+config MACH_PCM037_EET
+       bool "Support pcm037 EET board extensions"
+       depends on MACH_PCM037
+       help
+         Add support for PCM037 EET baseboard extensions. If you are using the
+         OLED display with EET, use "video=mx3fb:CMEL-OLED" kernel
+         command-line parameter.
+
 config MACH_MX31LITE
        bool "Support MX31 LITEKIT (LogicPD)"
        select ARCH_MX31
index 0322696bd11a19ad0402852b8858efe3750c6303..6b9775471be684d52e2d5fc53bc018d7ff0d3bf9 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_MACH_MX31ADS)    += mx31ads.o
 obj-$(CONFIG_MACH_MX31LILLY)   += mx31lilly.o mx31lilly-db.o
 obj-$(CONFIG_MACH_MX31LITE)    += mx31lite.o
 obj-$(CONFIG_MACH_PCM037)      += pcm037.o
+obj-$(CONFIG_MACH_PCM037_EET)  += pcm037_eet.o
 obj-$(CONFIG_MACH_MX31_3DS)    += mx31pdk.o
 obj-$(CONFIG_MACH_MX31MOBOARD) += mx31moboard.o mx31moboard-devboard.o \
                                   mx31moboard-marxbot.o
index 541181090b370dffca050e92d4a11bae94c0eb29..ee331fd6b1bd9c6e5f72159de2249e7d38e2fb7d 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/smsc911x.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/mmc.h>
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
+#include <mach/mxc_nand.h>
 
 #include "devices.h"
+#include "crm_regs.h"
 
 static int armadillo5x0_pins[] = {
        /* UART1 */
@@ -93,7 +97,56 @@ static int armadillo5x0_pins[] = {
        MX31_PIN_FPSHIFT__FPSHIFT,
        MX31_PIN_DRDY0__DRDY0,
        IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/
+};
 
+/*
+ * NAND Flash
+ */
+static struct mxc_nand_platform_data armadillo5x0_nand_flash_pdata = {
+       .width          = 1,
+       .hw_ecc         = 1,
+};
+
+/*
+ * MTD NOR Flash
+ */
+static struct mtd_partition armadillo5x0_nor_flash_partitions[] = {
+       {
+               .name           = "nor.bootloader",
+               .offset         = 0x00000000,
+               .size           = 4*32*1024,
+       }, {
+               .name           = "nor.kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 16*128*1024,
+       }, {
+               .name           = "nor.userland",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 110*128*1024,
+       }, {
+               .name           = "nor.config",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1*128*1024,
+       },
+};
+
+static struct physmap_flash_data armadillo5x0_nor_flash_pdata = {
+       .width          = 2,
+       .parts          = armadillo5x0_nor_flash_partitions,
+       .nr_parts       = ARRAY_SIZE(armadillo5x0_nor_flash_partitions),
+};
+
+static struct resource armadillo5x0_nor_flash_resource = {
+       .flags          = IORESOURCE_MEM,
+       .start          = CS0_BASE_ADDR,
+       .end            = CS0_BASE_ADDR + SZ_64M - 1,
+};
+
+static struct platform_device armadillo5x0_nor_flash = {
+       .name                   = "physmap-flash",
+       .id                     = -1,
+       .num_resources          = 1,
+       .resource               = &armadillo5x0_nor_flash_resource,
 };
 
 /*
@@ -272,6 +325,16 @@ static void __init armadillo5x0_init(void)
        /* Register FB */
        mxc_register_device(&mx3_ipu, &mx3_ipu_data);
        mxc_register_device(&mx3_fb, &mx3fb_pdata);
+
+       /* Register NOR Flash */
+       mxc_register_device(&armadillo5x0_nor_flash,
+                           &armadillo5x0_nor_flash_pdata);
+
+       /* Register NAND Flash */
+       mxc_register_device(&mxc_nand_device, &armadillo5x0_nand_flash_pdata);
+
+       /* set NAND page size to 2k if not configured via boot mode pins */
+       __raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR);
 }
 
 static void __init armadillo5x0_timer_init(void)
index d927eddcad460432200db70adf10ae4a5263f55e..9e87e08fb121f50288d8e98682b1d5e6d4a4aafa 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/gpio.h>
-#include <linux/dma-mapping.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/common.h>
index c6f61a1f06c8a2477bbc74e5111433abadbb0c6f..840cfda341d08c883489cc537d5ed851e93bd58d 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
-
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/plat-ram.h>
 #include <linux/irq.h>
 #include <linux/fsl_devices.h>
 
-#include <mach/hardware.h>
+#include <media/soc_camera.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <mach/board-pcm037.h>
 #include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/i2c.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/ipu.h>
-#include <mach/board-pcm037.h>
+#include <mach/mmc.h>
+#include <mach/mx3_camera.h>
 #include <mach/mx3fb.h>
 #include <mach/mxc_nand.h>
-#include <mach/mmc.h>
-#ifdef CONFIG_I2C_IMX
-#include <mach/i2c.h>
-#endif
 
 #include "devices.h"
+#include "pcm037.h"
+
+static enum pcm037_board_variant pcm037_instance = PCM037_PCM970;
+
+static int __init pcm037_variant_setup(char *str)
+{
+       if (!strcmp("eet", str))
+               pcm037_instance = PCM037_EET;
+       else if (strcmp("pcm970", str))
+               pr_warning("Unknown pcm037 baseboard variant %s\n", str);
+
+       return 1;
+}
+
+/* Supported values: "pcm970" (default) and "eet" */
+__setup("pcm037_variant=", pcm037_variant_setup);
+
+enum pcm037_board_variant pcm037_variant(void)
+{
+       return pcm037_instance;
+}
+
+/* UART1 with RTS/CTS handshake signals */
+static unsigned int pcm037_uart1_handshake_pins[] = {
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+};
+
+/* UART1 without RTS/CTS handshake signals */
+static unsigned int pcm037_uart1_pins[] = {
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+};
 
 static unsigned int pcm037_pins[] = {
        /* I2C */
        MX31_PIN_CSPI2_MOSI__SCL,
        MX31_PIN_CSPI2_MISO__SDA,
+       MX31_PIN_CSPI2_SS2__I2C3_SDA,
+       MX31_PIN_CSPI2_SCLK__I2C3_SCL,
        /* SDHC1 */
        MX31_PIN_SD1_DATA3__SD1_DATA3,
        MX31_PIN_SD1_DATA2__SD1_DATA2,
@@ -73,11 +111,6 @@ static unsigned int pcm037_pins[] = {
        MX31_PIN_CSPI1_SS0__SS0,
        MX31_PIN_CSPI1_SS1__SS1,
        MX31_PIN_CSPI1_SS2__SS2,
-       /* UART1 */
-       MX31_PIN_CTS1__CTS1,
-       MX31_PIN_RTS1__RTS1,
-       MX31_PIN_TXD1__TXD1,
-       MX31_PIN_RXD1__RXD1,
        /* UART2 */
        MX31_PIN_TXD2__TXD2,
        MX31_PIN_RXD2__RXD2,
@@ -120,6 +153,22 @@ static unsigned int pcm037_pins[] = {
        MX31_PIN_D3_SPL__D3_SPL,
        MX31_PIN_D3_CLS__D3_CLS,
        MX31_PIN_LCS0__GPI03_23,
+       /* CSI */
+       IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_GPIO),
+       MX31_PIN_CSI_D6__CSI_D6,
+       MX31_PIN_CSI_D7__CSI_D7,
+       MX31_PIN_CSI_D8__CSI_D8,
+       MX31_PIN_CSI_D9__CSI_D9,
+       MX31_PIN_CSI_D10__CSI_D10,
+       MX31_PIN_CSI_D11__CSI_D11,
+       MX31_PIN_CSI_D12__CSI_D12,
+       MX31_PIN_CSI_D13__CSI_D13,
+       MX31_PIN_CSI_D14__CSI_D14,
+       MX31_PIN_CSI_D15__CSI_D15,
+       MX31_PIN_CSI_HSYNC__CSI_HSYNC,
+       MX31_PIN_CSI_MCLK__CSI_MCLK,
+       MX31_PIN_CSI_PIXCLK__CSI_PIXCLK,
+       MX31_PIN_CSI_VSYNC__CSI_VSYNC,
 };
 
 static struct physmap_flash_data pcm037_flash_data = {
@@ -250,19 +299,43 @@ static struct mxc_nand_platform_data pcm037_nand_board_info = {
        .hw_ecc = 1,
 };
 
-#ifdef CONFIG_I2C_IMX
 static struct imxi2c_platform_data pcm037_i2c_1_data = {
        .bitrate = 100000,
 };
 
+static struct imxi2c_platform_data pcm037_i2c_2_data = {
+       .bitrate = 20000,
+};
+
 static struct at24_platform_data board_eeprom = {
        .byte_len = 4096,
        .page_size = 32,
        .flags = AT24_FLAG_ADDR16,
 };
 
+static int pcm037_camera_power(struct device *dev, int on)
+{
+       /* disable or enable the camera in X7 or X8 PCM970 connector */
+       gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), !on);
+       return 0;
+}
+
+static struct i2c_board_info pcm037_i2c_2_devices[] = {
+       {
+               I2C_BOARD_INFO("mt9t031", 0x5d),
+       },
+};
+
+static struct soc_camera_link iclink = {
+       .bus_id         = 0,            /* Must match with the camera ID */
+       .power          = pcm037_camera_power,
+       .board_info     = &pcm037_i2c_2_devices[0],
+       .i2c_adapter_id = 2,
+       .module_name    = "mt9t031",
+};
+
 static struct i2c_board_info pcm037_i2c_devices[] = {
-       {
+       {
                I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
                .platform_data = &board_eeprom,
        }, {
@@ -270,7 +343,14 @@ static struct i2c_board_info pcm037_i2c_devices[] = {
                .type = "pcf8563",
        }
 };
-#endif
+
+static struct platform_device pcm037_camera = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &iclink,
+       },
+};
 
 /* Not connected by default */
 #ifdef PCM970_SDHC_RW_SWITCH
@@ -334,9 +414,41 @@ static struct imxmmc_platform_data sdhc_pdata = {
        .exit = pcm970_sdhc1_exit,
 };
 
+struct mx3_camera_pdata camera_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .flags          = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10,
+       .mclk_10khz     = 2000,
+};
+
+static int __init pcm037_camera_alloc_dma(const size_t buf_size)
+{
+       dma_addr_t dma_handle;
+       void *buf;
+       int dma;
+
+       if (buf_size < 2 * 1024 * 1024)
+               return -EINVAL;
+
+       buf = dma_alloc_coherent(NULL, buf_size, &dma_handle, GFP_KERNEL);
+       if (!buf) {
+               pr_err("%s: cannot allocate camera buffer-memory\n", __func__);
+               return -ENOMEM;
+       }
+
+       memset(buf, 0, buf_size);
+
+       dma = dma_declare_coherent_memory(&mx3_camera.dev,
+                                       dma_handle, dma_handle, buf_size,
+                                       DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+
+       /* The way we call dma_declare_coherent_memory only a malloc can fail */
+       return dma & DMA_MEMORY_MAP ? 0 : -ENOMEM;
+}
+
 static struct platform_device *devices[] __initdata = {
        &pcm037_flash,
        &pcm037_sram_device,
+       &pcm037_camera,
 };
 
 static struct ipu_platform_data mx3_ipu_data = {
@@ -377,6 +489,22 @@ static const struct fb_videomode fb_modedb[] = {
                .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
                .vmode          = FB_VMODE_NONINTERLACED,
                .flag           = 0,
+       }, {
+               /* 240x320 @ 60 Hz */
+               .name           = "CMEL-OLED",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 185925,
+               .left_margin    = 9,
+               .right_margin   = 16,
+               .upper_margin   = 7,
+               .lower_margin   = 9,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
        },
 };
 
@@ -397,6 +525,14 @@ static void __init mxc_board_init(void)
        mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins),
                        "pcm037");
 
+       if (pcm037_variant() == PCM037_EET)
+               mxc_iomux_setup_multiple_pins(pcm037_uart1_pins,
+                       ARRAY_SIZE(pcm037_uart1_pins), "pcm037_uart1");
+       else
+               mxc_iomux_setup_multiple_pins(pcm037_uart1_handshake_pins,
+                       ARRAY_SIZE(pcm037_uart1_handshake_pins),
+                       "pcm037_uart1");
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata);
@@ -415,18 +551,30 @@ static void __init mxc_board_init(void)
        }
 
 
-#ifdef CONFIG_I2C_IMX
+       /* I2C adapters and devices */
        i2c_register_board_info(1, pcm037_i2c_devices,
                        ARRAY_SIZE(pcm037_i2c_devices));
 
        mxc_register_device(&mxc_i2c_device1, &pcm037_i2c_1_data);
-#endif
+       mxc_register_device(&mxc_i2c_device2, &pcm037_i2c_2_data);
+
        mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
        mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
        mxc_register_device(&mx3_ipu, &mx3_ipu_data);
        mxc_register_device(&mx3_fb, &mx3fb_pdata);
        if (!gpio_usbotg_hs_activate())
                mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+
+       /* CSI */
+       /* Camera power: default - off */
+       ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), "mt9t031-power");
+       if (!ret)
+               gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), 1);
+       else
+               iclink.power = NULL;
+
+       if (!pcm037_camera_alloc_dma(4 * 1024 * 1024))
+               mxc_register_device(&mx3_camera, &camera_pdata);
 }
 
 static void __init pcm037_timer_init(void)
@@ -448,4 +596,3 @@ MACHINE_START(PCM037, "Phytec Phycore pcm037")
        .init_machine   = mxc_board_init,
        .timer          = &pcm037_timer,
 MACHINE_END
-
diff --git a/arch/arm/mach-mx3/pcm037.h b/arch/arm/mach-mx3/pcm037.h
new file mode 100644 (file)
index 0000000..d692972
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PCM037_H__
+#define __PCM037_H__
+
+enum pcm037_board_variant {
+       PCM037_PCM970,
+       PCM037_EET,
+};
+
+extern enum pcm037_board_variant pcm037_variant(void);
+
+#endif
diff --git a/arch/arm/mach-mx3/pcm037_eet.c b/arch/arm/mach-mx3/pcm037_eet.c
new file mode 100644 (file)
index 0000000..fe52fb1
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * 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/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <mach/common.h>
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+#include <mach/spi.h>
+#endif
+#include <mach/iomux-mx3.h>
+
+#include <asm/mach-types.h>
+
+#include "pcm037.h"
+#include "devices.h"
+
+static unsigned int pcm037_eet_pins[] = {
+       /* SPI #1 */
+       MX31_PIN_CSPI1_MISO__MISO,
+       MX31_PIN_CSPI1_MOSI__MOSI,
+       MX31_PIN_CSPI1_SCLK__SCLK,
+       MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI1_SS0__SS0,
+       MX31_PIN_CSPI1_SS1__SS1,
+       MX31_PIN_CSPI1_SS2__SS2,
+
+       /* Reserve and hardwire GPIO 57 high - S6E63D6 chipselect */
+       IOMUX_MODE(MX31_PIN_KEY_COL7, IOMUX_CONFIG_GPIO),
+       /* GPIO keys */
+       IOMUX_MODE(MX31_PIN_GPIO1_0,    IOMUX_CONFIG_GPIO), /* 0 */
+       IOMUX_MODE(MX31_PIN_GPIO1_1,    IOMUX_CONFIG_GPIO), /* 1 */
+       IOMUX_MODE(MX31_PIN_GPIO1_2,    IOMUX_CONFIG_GPIO), /* 2 */
+       IOMUX_MODE(MX31_PIN_GPIO1_3,    IOMUX_CONFIG_GPIO), /* 3 */
+       IOMUX_MODE(MX31_PIN_SVEN0,      IOMUX_CONFIG_GPIO), /* 32 */
+       IOMUX_MODE(MX31_PIN_STX0,       IOMUX_CONFIG_GPIO), /* 33 */
+       IOMUX_MODE(MX31_PIN_SRX0,       IOMUX_CONFIG_GPIO), /* 34 */
+       IOMUX_MODE(MX31_PIN_SIMPD0,     IOMUX_CONFIG_GPIO), /* 35 */
+       IOMUX_MODE(MX31_PIN_RTS1,       IOMUX_CONFIG_GPIO), /* 38 */
+       IOMUX_MODE(MX31_PIN_CTS1,       IOMUX_CONFIG_GPIO), /* 39 */
+       IOMUX_MODE(MX31_PIN_KEY_ROW4,   IOMUX_CONFIG_GPIO), /* 50 */
+       IOMUX_MODE(MX31_PIN_KEY_ROW5,   IOMUX_CONFIG_GPIO), /* 51 */
+       IOMUX_MODE(MX31_PIN_KEY_ROW6,   IOMUX_CONFIG_GPIO), /* 52 */
+       IOMUX_MODE(MX31_PIN_KEY_ROW7,   IOMUX_CONFIG_GPIO), /* 53 */
+
+       /* LEDs */
+       IOMUX_MODE(MX31_PIN_DTR_DTE1,   IOMUX_CONFIG_GPIO), /* 44 */
+       IOMUX_MODE(MX31_PIN_DSR_DTE1,   IOMUX_CONFIG_GPIO), /* 45 */
+       IOMUX_MODE(MX31_PIN_KEY_COL5,   IOMUX_CONFIG_GPIO), /* 55 */
+       IOMUX_MODE(MX31_PIN_KEY_COL6,   IOMUX_CONFIG_GPIO), /* 56 */
+};
+
+/* SPI */
+static struct spi_board_info pcm037_spi_dev[] = {
+       {
+               .modalias       = "dac124s085",
+               .max_speed_hz   = 400000,
+               .bus_num        = 0,
+               .chip_select    = 0,            /* Index in pcm037_spi1_cs[] */
+               .mode           = SPI_CPHA,
+       },
+};
+
+/* Platform Data for MXC CSPI */
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)};
+
+struct spi_imx_master pcm037_spi1_master = {
+       .chipselect = pcm037_spi1_cs,
+       .num_chipselect = ARRAY_SIZE(pcm037_spi1_cs),
+};
+#endif
+
+/* GPIO-keys input device */
+static struct gpio_keys_button pcm037_gpio_keys[] = {
+       {
+               .type   = EV_KEY,
+               .code   = KEY_L,
+               .gpio   = 0,
+               .desc   = "Wheel Manual",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_A,
+               .gpio   = 1,
+               .desc   = "Wheel AF",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_V,
+               .gpio   = 2,
+               .desc   = "Wheel View",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_M,
+               .gpio   = 3,
+               .desc   = "Wheel Menu",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_UP,
+               .gpio   = 32,
+               .desc   = "Nav Pad Up",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_RIGHT,
+               .gpio   = 33,
+               .desc   = "Nav Pad Right",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_DOWN,
+               .gpio   = 34,
+               .desc   = "Nav Pad Down",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_LEFT,
+               .gpio   = 35,
+               .desc   = "Nav Pad Left",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_ENTER,
+               .gpio   = 38,
+               .desc   = "Nav Pad Ok",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = KEY_O,
+               .gpio   = 39,
+               .desc   = "Wheel Off",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = BTN_FORWARD,
+               .gpio   = 50,
+               .desc   = "Focus Forward",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = BTN_BACK,
+               .gpio   = 51,
+               .desc   = "Focus Backward",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = BTN_MIDDLE,
+               .gpio   = 52,
+               .desc   = "Release Half",
+               .wakeup = 0,
+       }, {
+               .type   = EV_KEY,
+               .code   = BTN_EXTRA,
+               .gpio   = 53,
+               .desc   = "Release Full",
+               .wakeup = 0,
+       },
+};
+
+static struct gpio_keys_platform_data pcm037_gpio_keys_platform_data = {
+       .buttons        = pcm037_gpio_keys,
+       .nbuttons       = ARRAY_SIZE(pcm037_gpio_keys),
+       .rep            = 0, /* No auto-repeat */
+};
+
+static struct platform_device pcm037_gpio_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &pcm037_gpio_keys_platform_data,
+       },
+};
+
+static int eet_init_devices(void)
+{
+       if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET)
+               return 0;
+
+       mxc_iomux_setup_multiple_pins(pcm037_eet_pins,
+                               ARRAY_SIZE(pcm037_eet_pins), "pcm037_eet");
+
+       /* SPI */
+       spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+       mxc_register_device(&mxc_spi_device0, &pcm037_spi1_master);
+#endif
+
+       platform_device_register(&pcm037_gpio_keys_device);
+
+       return 0;
+}
+
+late_initcall(eet_init_devices);
index ae8441192ef07a2d0c3ab7f07fafdbf2f974859b..7139e0dc26d16062304bd72beca1f339e61899e7 100644 (file)
 #define GPIO37_ULPI_DATA_OUT_7 MFP_CFG(GPIO37, AF3)
 #define GPIO33_ULPI_OTG_INTR   MFP_CFG(GPIO33, AF1)
 
-#define ULPI_DIR       MFP_CFG_DRV(ULPI_DIR, MFP_AF0, MFP_DS01X)
-#define ULPI_NXT       MFP_CFG_DRV(ULPI_NXT, MFP_AF0, MFP_DS01X)
-#define ULPI_STP       MFP_CFG_DRV(ULPI_STP, MFP_AF0, MFP_DS01X)
+#define ULPI_DIR       MFP_CFG_DRV(ULPI_DIR, AF0, DS01X)
+#define ULPI_NXT       MFP_CFG_DRV(ULPI_NXT, AF0, DS01X)
+#define ULPI_STP       MFP_CFG_DRV(ULPI_STP, AF0, DS01X)
 #endif /* CONFIG_CPU_PXA310 */
 
 #endif /* __ASM_ARCH_MFP_PXA300_H */
index 6f678d93bf4eb2f0da4b1a142c39945d127503be..09b7b1a10cadf9beb86fb51affa9bbea4ed26c11 100644 (file)
@@ -250,7 +250,7 @@ static DEFINE_PXA3_CKEN(pxa3xx_mmc2, MMC2, 19500000, 0);
 static struct clk_lookup pxa3xx_clkregs[] = {
        INIT_CLKREG(&clk_pxa3xx_pout, NULL, "CLK_POUT"),
        /* Power I2C clock is always on */
-       INIT_CLKREG(&clk_dummy, "pxa2xx-i2c.1", NULL),
+       INIT_CLKREG(&clk_dummy, "pxa3xx-pwri2c.1", NULL),
        INIT_CLKREG(&clk_pxa3xx_lcd, "pxa2xx-fb", NULL),
        INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"),
        INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"),
index 9ea9c05093cd47afed1d6798d5a2eeb9d9333f43..facbd49eec67e30bb1d3dbfedf2364fe964a1cdc 100644 (file)
@@ -208,8 +208,7 @@ struct platform_device realview_i2c_device = {
 
 static struct i2c_board_info realview_i2c_board_info[] = {
        {
-               I2C_BOARD_INFO("rtc-ds1307", 0xd0 >> 1),
-               .type = "ds1338",
+               I2C_BOARD_INFO("ds1338", 0xd0 >> 1),
        },
 };
 
index 89b3ccf35e1bbf74740c2c856f03ad908b694fe9..7936085dd75881c3faca30adcbede5a8ba60db56 100644 (file)
@@ -455,8 +455,8 @@ void __init u300_init_irq(void)
        for (i = 0; i < NR_IRQS; i++)
                set_bit(i, (unsigned long *) &mask[0]);
        u300_enable_intcon_clock();
-       vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], 0);
-       vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], 0);
+       vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], mask[0]);
+       vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], mask[1]);
 }
 
 
index 69214fc8bd19576093accb6904549ecc2e12fa0c..31093af7d05211ba940d80d6700291257db1bb6c 100644 (file)
@@ -342,8 +342,7 @@ static struct platform_device versatile_i2c_device = {
 
 static struct i2c_board_info versatile_i2c_board_info[] = {
        {
-               I2C_BOARD_INFO("rtc-ds1307", 0xd0 >> 1),
-               .type = "ds1338",
+               I2C_BOARD_INFO("ds1338", 0xd0 >> 1),
        },
 };
 
index 27f8d1b2bc6ba611bc0759b1900f81a39182c9d9..2eb182f73876acfc1c33965d2e82e3f20a23360f 100644 (file)
@@ -602,6 +602,8 @@ enum iomux_pins {
 #define MX31_PIN_I2C_DAT__SDA          IOMUX_MODE(MX31_PIN_I2C_DAT, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_DCD_DTE1__I2C2_SDA    IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_RI_DTE1__I2C2_SCL     IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_CSPI2_SS2__I2C3_SDA   IOMUX_MODE(MX31_PIN_CSPI2_SS2, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_CSPI2_SCLK__I2C3_SCL  IOMUX_MODE(MX31_PIN_CSPI2_SCLK, IOMUX_CONFIG_ALT1)
 #define MX31_PIN_CSI_D4__CSI_D4                IOMUX_MODE(MX31_PIN_CSI_D4, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSI_D5__CSI_D5                IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSI_D6__CSI_D6                IOMUX_MODE(MX31_PIN_CSI_D6, IOMUX_CONFIG_FUNC)
index abc79d44acaacd472a3f1996c5c060487cbeba08..98548c6903a08aadff48196e2c4f6148968fc83d 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/sysdev.h>
-#include <linux/bootmem.h>
+#include <linux/slab.h>
 
 #include <mach/gpio.h>
 
@@ -112,17 +112,12 @@ static int __init pxa_init_gpio_chip(int gpio_end)
        int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
        struct pxa_gpio_chip *chips;
 
-       /* this is early, we have to use bootmem allocator, and we really
-        * want this to be allocated dynamically for different 'gpio_end'
-        */
-       chips = alloc_bootmem_low(nbanks * sizeof(struct pxa_gpio_chip));
+       chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
        if (chips == NULL) {
                pr_err("%s: failed to allocate GPIO chips\n", __func__);
                return -ENOMEM;
        }
 
-       memset(chips, 0, nbanks * sizeof(struct pxa_gpio_chip));
-
        for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
                struct gpio_chip *c = &chips[i].chip;
 
index 64082132394312a4c861abdc6b110f58517a7a40..92ecd8446ef80b6fe06c62bce45fe93a40f344bb 100644 (file)
@@ -83,7 +83,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,addr)                   \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), pte);                    \
index 4442f8d2d4239a09470e04583aa9f168583246d9..fc42de5ca209ac5e9de0cfca9c1f35561f740be2 100644 (file)
@@ -40,7 +40,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain,                         \
        .flags          = 0,                                            \
        .cpu            = 0,                                            \
-       .preempt_count  = 1,                                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,                           \
        .restart_block  = {                                             \
                .fn     = do_no_restart_syscall                         \
        }                                                               \
index 16561ab18b38b602a9426a9f0c6c0b8bcb8aac93..f8a664f022b1ad1022bf7c9aa842e369124e4808 100644 (file)
        [--sp] = RETN;
        [--sp] = RETE;
        [--sp] = SEQSTAT;
-#ifdef CONFIG_KGDB
-       r1.l = lo(IPEND);
-       r1.h = hi(IPEND);
+#ifdef CONFIG_DEBUG_KERNEL
+       p1.l = lo(IPEND);
+       p1.h = hi(IPEND);
+       r1 = [p1];
        [--sp] = r1;
 #else
        [--sp] = r0;    /* Skip IPEND as well. */
index 565b8136855ed16d5237376cc7186878dcc46855..fadfa82f93b2d11c3ffa3cbfa9324a10c4b94261 100644 (file)
@@ -32,7 +32,6 @@ struct blackfin_cpudata {
        struct task_struct *idle;
        unsigned int imemctl;
        unsigned int dmemctl;
-       unsigned long loops_per_jiffy;
        unsigned long dcache_invld_count;
        unsigned long icache_invld_count;
 };
index cbd52f86bb9f752ce8f33dff091546e815a3ed38..0b78b873df5103fca28d39673703a4aac45e3e04 100644 (file)
@@ -6,6 +6,9 @@
 extern void ack_bad_irq(unsigned int irq);
 #define ack_bad_irq ack_bad_irq
 
+/* Define until common code gets sane defaults */
+#define HARDIRQ_BITS 9
+
 #include <asm-generic/hardirq.h>
 
 #endif
index d0be99be8308d3a9324dacae900939f384e6f1e0..a36ad8dac0681914dd067af2a6c1609d39e475c5 100644 (file)
@@ -105,23 +105,16 @@ static inline uint32_t __pure bfin_revid(void)
        /* Always use CHIPID, to work around ANOMALY_05000234 */
        uint32_t revid = (bfin_read_CHIPID() & CHIPID_VERSION) >> 28;
 
-#ifdef CONFIG_BF52x
-       /* ANOMALY_05000357
+#ifdef _BOOTROM_GET_DXE_ADDRESS_TWI
+       /*
+        * ANOMALY_05000364
         * Incorrect Revision Number in DSPID Register
         */
-       if (revid == 0)
-               switch (bfin_read16(_BOOTROM_GET_DXE_ADDRESS_TWI)) {
-               case 0x0010:
-                       revid = 0;
-                       break;
-               case 0x2796:
-                       revid = 1;
-                       break;
-               default:
-                       revid = 0xFFFF;
-                       break;
-               }
+       if (ANOMALY_05000364 &&
+           bfin_read16(_BOOTROM_GET_DXE_ADDRESS_TWI) == 0x2796)
+               revid = 1;
 #endif
+
        return revid;
 }
 
index 2920087516f2a08175b54ed3086844434db937c9..2bbfdd950afc49c4623d876125b0a71dd7de4903 100644 (file)
@@ -77,7 +77,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index e0bf8cc06907abd67040c37127f0091792c39a8a..9f9b82816652d6bddc4c67199699d9ba22647e1f 100644 (file)
@@ -253,32 +253,31 @@ void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
        BUG_ON(src % 4);
        BUG_ON(size % 4);
 
-       /* Force a sync in case a previous config reset on this channel
-        * occurred.  This is needed so subsequent writes to DMA registers
-        * are not spuriously lost/corrupted.
-        */
-       __builtin_bfin_ssync();
-
        src_ch = 0;
        /* Find an avalible memDMA channel */
        while (1) {
-               if (!src_ch || src_ch == (struct dma_register *)MDMA_S1_NEXT_DESC_PTR) {
-                       dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
-                       src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
-               } else {
+               if (src_ch == (struct dma_register *)MDMA_S0_NEXT_DESC_PTR) {
                        dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR;
                        src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR;
+               } else {
+                       dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
+                       src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
                }
 
-               if (!bfin_read16(&src_ch->cfg)) {
+               if (!bfin_read16(&src_ch->cfg))
+                       break;
+               else if (bfin_read16(&dst_ch->irq_status) & DMA_DONE) {
+                       bfin_write16(&src_ch->cfg, 0);
                        break;
-               } else {
-                       if (bfin_read16(&src_ch->irq_status) & DMA_DONE)
-                               bfin_write16(&src_ch->cfg, 0);
                }
-
        }
 
+       /* Force a sync in case a previous config reset on this channel
+        * occurred.  This is needed so subsequent writes to DMA registers
+        * are not spuriously lost/corrupted.
+        */
+       __builtin_bfin_ssync();
+
        /* Destination */
        bfin_write32(&dst_ch->start_addr, dst);
        bfin_write16(&dst_ch->x_count, size >> 2);
index beffa00a93c3a6e2d98f236e82f1653e232c40e8..6b94462713710b612f3fb82e351b92d5e5bdb46a 100644 (file)
@@ -686,14 +686,12 @@ void bfin_gpio_pm_hibernate_restore(void)
                *port_fer[bank] = gpio_bank_saved[bank].fer;
 #endif
                gpio_array[bank]->inen  = gpio_bank_saved[bank].inen;
+               gpio_array[bank]->data_set = gpio_bank_saved[bank].data
+                                               & gpio_bank_saved[bank].dir;
                gpio_array[bank]->dir   = gpio_bank_saved[bank].dir;
                gpio_array[bank]->polar = gpio_bank_saved[bank].polar;
                gpio_array[bank]->edge  = gpio_bank_saved[bank].edge;
                gpio_array[bank]->both  = gpio_bank_saved[bank].both;
-
-               gpio_array[bank]->data_set = gpio_bank_saved[bank].data
-                                               | gpio_bank_saved[bank].dir;
-
                gpio_array[bank]->maska = gpio_bank_saved[bank].maska;
        }
        AWA_DUMMY_READ(maska);
index d6c067782e638987ba406164f6df65adeb0b15db..685f160a5a369789671f948e2132d36fb5c2e29b 100644 (file)
@@ -72,13 +72,24 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
        }
 
        /* Cover L1 memory.  One 4M area for code and data each is enough.  */
-       if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) {
-               d_tbl[i_d].addr = L1_DATA_A_START;
-               d_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
+       if (cpu == 0) {
+               if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) {
+                       d_tbl[i_d].addr = L1_DATA_A_START;
+                       d_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
+               }
+               i_tbl[i_i].addr = L1_CODE_START;
+               i_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
        }
-       i_tbl[i_i].addr = L1_CODE_START;
-       i_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
-
+#ifdef CONFIG_SMP
+       else {
+               if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) {
+                       d_tbl[i_d].addr = COREB_L1_DATA_A_START;
+                       d_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
+               }
+               i_tbl[i_i].addr = COREB_L1_CODE_START;
+               i_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
+       }
+#endif
        first_switched_dcplb = i_d;
        first_switched_icplb = i_i;
 
index 79cad0ac5892eacdcb153e046eb3ee6115c5c69d..9da36bab7ccb10194a3cde2c40628f4e52aeeccb 100644 (file)
@@ -361,7 +361,7 @@ static inline
 int in_mem_const(unsigned long addr, unsigned long size,
                  unsigned long const_addr, unsigned long const_size)
 {
-       return in_mem_const_off(addr, 0, size, const_addr, const_size);
+       return in_mem_const_off(addr, size, 0, const_addr, const_size);
 }
 #define IN_ASYNC(bnum, bctlnum) \
 ({ \
@@ -390,13 +390,13 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size)
        if (in_mem_const(addr, size, L1_DATA_B_START, L1_DATA_B_LENGTH))
                return cpu == 0 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
 #ifdef COREB_L1_CODE_START
-       if (in_mem_const(addr, size, COREB_L1_CODE_START, L1_CODE_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH))
                return cpu == 1 ? BFIN_MEM_ACCESS_ITEST : BFIN_MEM_ACCESS_IDMA;
        if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH))
                return cpu == 1 ? BFIN_MEM_ACCESS_CORE_ONLY : -EFAULT;
-       if (in_mem_const(addr, size, COREB_L1_DATA_A_START, L1_DATA_A_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH))
                return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
-       if (in_mem_const(addr, size, COREB_L1_DATA_B_START, L1_DATA_B_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
                return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
 #endif
        if (in_mem_const(addr, size, L2_START, L2_LENGTH))
@@ -472,13 +472,13 @@ int _access_ok(unsigned long addr, unsigned long size)
        if (in_mem_const_off(addr, size, _ebss_b_l1 - _sdata_b_l1, L1_DATA_B_START, L1_DATA_B_LENGTH))
                return 1;
 #ifdef COREB_L1_CODE_START
-       if (in_mem_const(addr, size, COREB_L1_CODE_START, L1_CODE_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH))
                return 1;
        if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH))
                return 1;
-       if (in_mem_const(addr, size, COREB_L1_DATA_A_START, L1_DATA_A_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH))
                return 1;
-       if (in_mem_const(addr, size, COREB_L1_DATA_B_START, L1_DATA_B_LENGTH))
+       if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
                return 1;
 #endif
        if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH))
index d76618db50df8c4e3f4c06cb44d09906e5b41147..6a387eec6b65e5baa3bcfb247e037748bea6f587 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 6136c33e919f79b700efcac55623eaf5a53f1911..6225edae488edeb713db588487fe709d839572eb 100644 (file)
@@ -168,7 +168,6 @@ void __cpuinit bfin_setup_cpudata(unsigned int cpu)
        struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu);
 
        cpudata->idle = current;
-       cpudata->loops_per_jiffy = loops_per_jiffy;
        cpudata->imemctl = bfin_read_IMEM_CONTROL();
        cpudata->dmemctl = bfin_read_DMEM_CONTROL();
 }
@@ -568,17 +567,23 @@ static __init void memory_setup(void)
 #  endif                               /* ANOMALY_05000263 */
 # endif                                /* CONFIG_ROMFS_FS */
 
-       memory_end -= mtd_size;
-
-       if (mtd_size == 0) {
-               console_init();
-               panic("Don't boot kernel without rootfs attached.");
+       /* Since the default MTD_UCLINUX has no magic number, we just blindly
+        * read 8 past the end of the kernel's image, and look at it.
+        * When no image is attached, mtd_size is set to a random number
+        * Do some basic sanity checks before operating on things
+        */
+       if (mtd_size == 0 || memory_end <= mtd_size) {
+               pr_emerg("Could not find valid ram mtd attached.\n");
+       } else {
+               memory_end -= mtd_size;
+
+               /* Relocate MTD image to the top of memory after the uncached memory area */
+               uclinux_ram_map.phys = memory_mtd_start = memory_end;
+               uclinux_ram_map.size = mtd_size;
+               pr_info("Found mtd parition at 0x%p, (len=0x%lx), moving to 0x%p\n",
+                       _end, mtd_size, (void *)memory_mtd_start);
+               dma_memcpy((void *)uclinux_ram_map.phys, _end, uclinux_ram_map.size);
        }
-
-       /* Relocate MTD image to the top of memory after the uncached memory area */
-       uclinux_ram_map.phys = memory_mtd_start = memory_end;
-       uclinux_ram_map.size = mtd_size;
-       dma_memcpy((void *)uclinux_ram_map.phys, _end, uclinux_ram_map.size);
 #endif                         /* CONFIG_MTD_UCLINUX */
 
 #if (defined(CONFIG_BFIN_EXTMEM_ICACHEABLE) && ANOMALY_05000263)
@@ -868,13 +873,6 @@ void __init setup_arch(char **cmdline_p)
        else
                printk(KERN_CONT "and Disabled\n");
 
-#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
-       /* we need to initialize the Flashrom device here since we might
-        * do things with flash early on in the boot
-        */
-       flash_probe();
-#endif
-
        printk(KERN_INFO "Boot Mode: %i\n", bfin_read_SYSCR() & 0xF);
 
        /* Newer parts mirror SWRST bits in SYSCR */
@@ -938,10 +936,6 @@ void __init setup_arch(char **cmdline_p)
                               CPU, bfin_revid());
        }
 
-       /* We can't run on BF548-0.1 due to ANOMALY 05000448 */
-       if (bfin_cpuid() == 0x27de && bfin_revid() == 1)
-               panic("You can't run on this processor due to 05000448");
-
        printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
 
        printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
@@ -1164,9 +1158,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                sclk/1000000, sclk%1000000);
        seq_printf(m, "bogomips\t: %lu.%02lu\n"
                "Calibration\t: %lu loops\n",
-               (cpudata->loops_per_jiffy * HZ) / 500000,
-               ((cpudata->loops_per_jiffy * HZ) / 5000) % 100,
-               (cpudata->loops_per_jiffy * HZ));
+               (loops_per_jiffy * HZ) / 500000,
+               ((loops_per_jiffy * HZ) / 5000) % 100,
+               (loops_per_jiffy * HZ));
 
        /* Check Cache configutation */
        switch (cpudata->dmemctl & (1 << DMC0_P | 1 << DMC1_P)) {
index a8f1329c15a48befeb62f31a7b80603b263dda2d..3da60fb13ce46d8a45b5194e152985608c0cbaeb 100644 (file)
@@ -29,7 +29,6 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
index 8a1caf2bb5b9defa94dc1fff7c6803afb3324fad..bf2b2d1f8ae5f35ecd64b68abbbc324f444fa421 100644 (file)
@@ -570,11 +570,12 @@ asmlinkage void trap_c(struct pt_regs *fp)
        if (kernel_mode_regs(fp) || (current && !current->mm)) {
                console_verbose();
                oops_in_progress = 1;
-               if (strerror)
-                       verbose_printk(strerror);
        }
 
        if (sig != SIGTRAP) {
+               if (strerror)
+                       verbose_printk(strerror);
+
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
                show_regs(fp);
@@ -619,7 +620,9 @@ asmlinkage void trap_c(struct pt_regs *fp)
                force_sig_info(sig, &info, current);
        }
 
-       if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
+       if ((ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8)) ||
+           (ANOMALY_05000281 && trapnr == VEC_HWERR) ||
+           (ANOMALY_05000189 && (trapnr == VEC_CPLB_I_VL || trapnr == VEC_CPLB_VL)))
                fp->pc = SAFE_USER_INSTRUCTION;
 
  traps_done:
index 84b9c5592220eac8648306a57295047b21456671..e57bf6fbdf3f4040bee13652a35c984b8cc45d85 100644 (file)
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#define BITS_PER_UNIT 8
-
-typedef int SItype __attribute__ ((mode(SI)));
-typedef unsigned int USItype __attribute__ ((mode(SI)));
-typedef int DItype __attribute__ ((mode(DI)));
-typedef int word_type __attribute__ ((mode(__word__)));
-
-struct DIstruct {
-       SItype high, low;
-};
-
-typedef union {
-       struct DIstruct s;
-       DItype ll;
-} DIunion;
+#include "gcclib.h"
 
 #ifdef CONFIG_ARITHMETIC_OPS_L1
 DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
index d9791106be9f71b16187201736815a09bcfa8445..809be268e42d4fcdf20ea802bb35bb1d87677559 100644 (file)
@@ -534,7 +534,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 426e064062a0322ed4a21fe29096869fdcf71cce..753ed810e1c61f8bc0b63d6a117c82504f3fbd9e 100644 (file)
@@ -82,6 +82,7 @@
 #define ANOMALY_05000179 (0)
 #define ANOMALY_05000182 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000189 (0)
 #define ANOMALY_05000198 (0)
 #define ANOMALY_05000202 (0)
 #define ANOMALY_05000215 (0)
 #define ANOMALY_05000357 (0)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000371 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (0)
index 0fb2ce5d840e14ae73ba9058d19e4da9f3bd0733..dbade93395eb2b996e1467702504436a6c97c958 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index f4867ce0c618b89f64c9d634739f65bf8934de89..b09484f538f41abdf1ebf69ebd48acb7fe61f9c4 100644 (file)
@@ -793,7 +793,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
                .type = "pcf8574_lcd",
index b2f30f06b73e2290b40bc518d292c0a135ed6f14..2ad68cd10ae674af6b7d693afb98f7cbcdc79320 100644 (file)
@@ -591,7 +591,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 799a1d1fa89044f87eae1691350199fae081f851..75e563d3f9d4f0f49aa87921a11781e8fbcbd01b 100644 (file)
@@ -858,7 +858,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 0d63f7406168cd154684dd352c9b741f8f7ec8b0..c438ca89d8c9047c71669ffd652d67a92f135eb1 100644 (file)
 #define ANOMALY_05000443 (1)
 /* The WURESET Bit in the SYSCR Register is not Functional */
 #define ANOMALY_05000445 (1)
+/* USB DMA Short Packet Data Corruption */
+#define ANOMALY_05000450 (1)
 /* BCODE_QUICKBOOT, BCODE_ALLBOOT, and BCODE_FULLBOOT Settings in SYSCR Register Not Functional */
 #define ANOMALY_05000451 (1)
 /* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */
 #define ANOMALY_05000179 (0)
 #define ANOMALY_05000182 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000189 (0)
 #define ANOMALY_05000198 (0)
 #define ANOMALY_05000202 (0)
 #define ANOMALY_05000215 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
-#define ANOMALY_05000450 (0)
 
 #endif
index a625659dd67f4470d0ff310e833362ddd6ff3ebe..ebd6cebc1fbc40bd500b6df924b05fd81b1b53f7 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index a68ade8a3ca2a876c721c030efa84dfa01087d0d..3d743ccaff6ab8d4b543b091f72833b8c8f73a21 100644 (file)
@@ -453,7 +453,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                .irq = 39,
        },
 #endif
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 70a0ad69c6106f94c95a4b835cb917d4c086880c..cd83db2fb1a17fdc99e3cba7a7423005430afc80 100644 (file)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000362 (1)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
index a3789d7ccf8c233c4fc182be215ba7585742c7c8..4062e24e759bbc83eb51dedf8386fb7dcc9792bd 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index c1f76dd2c4ed50aac0fb806098e776854782b8b7..bd656907b8c01588983d0f4e3c1cf267679d0c5c 100644 (file)
@@ -1313,10 +1313,10 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
        {
                I2C_BOARD_INFO("ad7142_joystick", 0x2C),
-               .irq = IRQ_PF5,
+               .irq = IRQ_PG5,
        },
 #endif
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 57c128cc3b6480a57762e5269bbccfb9365a6718..e66aa131f517d66ec5fe17588bf71d5f8c1cb7ef 100644 (file)
 #define ANOMALY_05000179 (0)
 #define ANOMALY_05000182 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000189 (0)
 #define ANOMALY_05000198 (0)
 #define ANOMALY_05000202 (0)
 #define ANOMALY_05000215 (0)
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
index b86662fb9de76fad4cf16b0ee3a46e5d81db4d32..e95d54f9af6c008075cb9529b47e066ac376cc4d 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index c97acdf85cd3020b70a362b17ceb53e16464813f..451cf8a82a42b0e1edbb3525232cf485587158af 100644 (file)
 #define ANOMALY_05000158 (0)
 #define ANOMALY_05000171 (0)
 #define ANOMALY_05000182 (0)
+#define ANOMALY_05000189 (0)
 #define ANOMALY_05000198 (0)
 #define ANOMALY_05000202 (0)
 #define ANOMALY_05000215 (0)
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
index c536551eb4b8ff64dd35194d9270e32014aa8704..999f239fe1a6376373efe75f5424398d48308ee1 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index 81f5b95cc3612d1592765274056c090627c6dfff..dc0dd9b2bcef46383369795cda3a3a19264e2fe4 100644 (file)
@@ -864,7 +864,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info0[] = {
 
 #if !defined(CONFIG_BF542)     /* The BF542 only has 1 TWI */
 static struct i2c_board_info __initdata bfin_i2c_board_info1[] = {
-#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 18a4cd24f6732492bfeb9ed2bbb5ededb30f38fb..cd040fe0bc5c10e47b38f6fbd1882d5f3dbdad34 100644 (file)
 #define ANOMALY_05000179 (0)
 #define ANOMALY_05000182 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000189 (0)
 #define ANOMALY_05000198 (0)
 #define ANOMALY_05000202 (0)
 #define ANOMALY_05000215 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
index 94b8e277f09d1d1773291fc6065c4be73e0b285a..a5312b2d267e25117d53a6875f0ffcc0c75c4e9c 100644 (file)
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
index a1b50878553fbfc462e63a869a5ab7be1c190722..fd5e8878b8c419f73f99b84d89a5db7b96748173 100644 (file)
@@ -53,7 +53,7 @@
 #define UART_SET_DLAB(uart)     do { UART_PUT_LCR(uart, UART_GET_LCR(uart) | DLAB); SSYNC(); } while (0)
 #define UART_CLEAR_DLAB(uart)   do { UART_PUT_LCR(uart, UART_GET_LCR(uart) & ~DLAB); SSYNC(); } while (0)
 
-#define UART_GET_CTS(x) (!gpio_get_value(x->cts_pin))
+#define UART_GET_CTS(x) gpio_get_value(x->cts_pin)
 #define UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
 #define UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
 #define UART_ENABLE_INTS(x, v) UART_PUT_IER(x, v)
index a63e15c86d90438dec954ce6b6d883682e13374a..5b96ea549a049bb00a902e779da827e338d6d9da 100644 (file)
@@ -37,7 +37,6 @@
 
 /* Memory Map for ADSP-BF561 processors */
 
-#ifdef CONFIG_BF561
 #define COREA_L1_CODE_START       0xFFA00000
 #define COREA_L1_DATA_A_START     0xFF800000
 #define COREA_L1_DATA_B_START     0xFF900000
 #define BFIN_DCACHESIZE        (0*1024)
 #define BFIN_DSUPBANKS 0
 #endif /*CONFIG_BFIN_DCACHE*/
+
+/*
+ * If we are in SMP mode, then the cache settings of Core B will match
+ * the settings of Core A.  If we aren't, then we assume Core B is not
+ * using any cache.  This allows the rest of the kernel to work with
+ * the core in either mode as we are only loading user code into it and
+ * it is the user's problem to make sure they aren't doing something
+ * stupid there.
+ *
+ * Note that we treat the L1 code region as a contiguous blob to make
+ * the rest of the kernel simpler.  Easier to check one region than a
+ * bunch of small ones.  Again, possible misbehavior here is the fault
+ * of the user -- don't try to use memory that doesn't exist.
+ */
+#ifdef CONFIG_SMP
+# define COREB_L1_CODE_LENGTH     L1_CODE_LENGTH
+# define COREB_L1_DATA_A_LENGTH   L1_DATA_A_LENGTH
+# define COREB_L1_DATA_B_LENGTH   L1_DATA_B_LENGTH
+#else
+# define COREB_L1_CODE_LENGTH     0x14000
+# define COREB_L1_DATA_A_LENGTH   0x8000
+# define COREB_L1_DATA_B_LENGTH   0x8000
 #endif
 
 /* Level 2 Memory */
index 5a4e7c7fd92c4e0976ce58f1bf977b6911390775..fb1795d5be2af2e9765f31c1c40fafd90257580e 100644 (file)
@@ -218,7 +218,7 @@ ENTRY(_ex_single_step)
        /* Single stepping only a single instruction, so clear the trace
         * bit here.  */
        r7 = syscfg;
-       bitclr (r7, 0);
+       bitclr (r7, SYSCFG_SSSTEP_P);
        syscfg = R7;
        jump _ex_trap_c;
 
@@ -251,7 +251,7 @@ ENTRY(_ex_single_step)
        if !cc jump _bfin_return_from_exception;
 
        r7 = syscfg;
-       bitclr (r7, 0);
+       bitclr (r7, SYSCFG_SSSTEP_P);   /* Turn off single step */
        syscfg = R7;
 
        /* Fall through to _bfin_return_from_exception.  */
@@ -342,9 +342,11 @@ ENTRY(_ex_trap_c)
        r6 = retx;
        [p5 + PDA_RETX] = r6;
 #endif
+       /* Save the state of single stepping */
        r6 = SYSCFG;
        [p5 + PDA_SYSCFG] = r6;
-       BITCLR(r6, 0);
+       /* Clear it while we handle the exception in IRQ5 mode */
+       BITCLR(r6, SYSCFG_SSSTEP_P);
        SYSCFG = r6;
 
        /* Disable all interrupts, but make sure level 5 is enabled so
@@ -367,7 +369,7 @@ ENDPROC(_ex_trap_c)
  * exception. This is a unrecoverable event, so crash.
  * Note: this cannot be ENTRY() as we jump here with "if cc jump" ...
  */
-_double_fault:
+ENTRY(_double_fault)
        /* Turn caches & protection off, to ensure we don't get any more
         * double exceptions
         */
@@ -872,7 +874,7 @@ ENTRY(_ret_from_exception)
        raise 15;               /* raise evt15 to do signal or reschedule */
 4:
        r0 = syscfg;
-       bitclr(r0, 0);
+       bitclr(r0, SYSCFG_SSSTEP_P);            /* Turn off single step */
        syscfg = r0;
 5:
        rts;
index 61840059dfac30feb314fcf373f4ef51dea943cd..349ee3f5466a8dd089902e335e765e1492563509 100644 (file)
@@ -211,6 +211,8 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
                return 0;
 
        msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+       if (!msg)
+               return -ENOMEM;
        INIT_LIST_HEAD(&msg->list);
        msg->call_struct.func = func;
        msg->call_struct.info = info;
@@ -252,6 +254,8 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
        cpu_set(cpu, callmap);
 
        msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+       if (!msg)
+               return -ENOMEM;
        INIT_LIST_HEAD(&msg->list);
        msg->call_struct.func = func;
        msg->call_struct.info = info;
@@ -287,6 +291,8 @@ void smp_send_reschedule(int cpu)
                return;
 
        msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+       if (!msg)
+               return;
        memset(msg, 0, sizeof(msg));
        INIT_LIST_HEAD(&msg->list);
        msg->type = BFIN_IPI_RESCHEDULE;
@@ -314,6 +320,8 @@ void smp_send_stop(void)
                return;
 
        msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+       if (!msg)
+               return;
        memset(msg, 0, sizeof(msg));
        INIT_LIST_HEAD(&msg->list);
        msg->type = BFIN_IPI_CPU_STOP;
@@ -450,7 +458,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
        unsigned int cpu;
 
        for_each_online_cpu(cpu)
-               bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy;
+               bogosum += loops_per_jiffy;
 
        printk(KERN_INFO "SMP: Total of %d processors activated "
               "(%lu.%02lu BogoMIPS).\n",
index a1ba761d0573637ffb79ff4f9d6624d644dad9ce..6da975db112fdabff1125ed0f3ecb38df892caae 100644 (file)
@@ -47,7 +47,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,address)                        \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), pte);                    \
index bc5b2935ca53a782c66acf4c371e87e46de39077..c3aade36c330400cb7dceb69051a422bb16ed34a 100644 (file)
@@ -50,8 +50,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)                          \
@@ -60,7 +58,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain,         \
        .flags          = 0,                            \
        .cpu            = 0,                            \
-       .preempt_count  = 1,                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,           \
        .addr_limit     = KERNEL_DS,                    \
        .restart_block = {                              \
                       .fn = do_no_restart_syscall,     \
index a79fbd87021b02cf03663f7a06d680a58a24ceac..2ad962c7e88ebaddcbc11ed7a3a88f3e2e900385 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index 971e6addb0095a4175d86b68715937e918d2f474..416d19a632f228a30f1133df32fc1629fa359731 100644 (file)
@@ -49,7 +49,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,address)                        \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb),(pte));                   \
@@ -62,7 +62,7 @@ do {                                                  \
  */
 #define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *) 2); })
 #define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb,x)          do { } while (0)
+#define __pmd_free_tlb(tlb,x,a)                do { } while (0)
 
 #endif /* CONFIG_MMU */
 
index 33233011b1c1147ff46d2aaac3522150d72630c7..22c60692b5513c7c6f66d49947a16e574ba31835 100644 (file)
@@ -225,7 +225,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
  */
 #define pud_alloc_one(mm, address)             NULL
 #define pud_free(mm, x)                                do { } while (0)
-#define __pud_free_tlb(tlb, x                do { } while (0)
+#define __pud_free_tlb(tlb, x, address)                do { } while (0)
 
 /*
  * The "pud_xxx()" functions here are trivial for a folded two-level
index e8a5ed7be0212791674996fd16afeb4f38a6b751..e608e056bb5301582b44b13d2bba9d9ccabfc23a 100644 (file)
@@ -56,8 +56,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -67,7 +65,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 700014d2155fd8d82a4aeadb54c4b3ad682855bb..8bbc8b0ee45db3ad2ddb97f6c6c9be4b5550315f 100644 (file)
@@ -36,7 +36,7 @@ struct thread_info {
        .exec_domain =  &default_exec_domain,   \
        .flags =        0,                      \
        .cpu =          0,                      \
-       .preempt_count = 1,                     \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 0c26157cffa55fe0ea1c348fd0a542b11e6c46c3..b6395ad1500a00f7d2a133b3633bed96fd91be2f 100644 (file)
@@ -6,6 +6,8 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
+#include <linux/types.h>
+
 /* floating point status register: */
 #define FPSR_TRAP_VD   (1 << 0)        /* invalid op trap disabled */
 #define FPSR_TRAP_DD   (1 << 1)        /* denormal trap disabled */
index b9ac1a6fc21694a55e2771e471ab8cc90ab997cf..96a8d927db2851c9c17d8b48f6b47da66f9dd572 100644 (file)
@@ -48,7 +48,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
        quicklist_free(0, NULL, pud);
 }
-#define __pud_free_tlb(tlb, pud      pud_free((tlb)->mm, pud)
+#define __pud_free_tlb(tlb, pud, address)      pud_free((tlb)->mm, pud)
 #endif /* CONFIG_PGTABLE_4 */
 
 static inline void
@@ -67,7 +67,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        quicklist_free(0, NULL, pmd);
 }
 
-#define __pmd_free_tlb(tlb, pmd      pmd_free((tlb)->mm, pmd)
+#define __pmd_free_tlb(tlb, pmd, address)      pmd_free((tlb)->mm, pmd)
 
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, pgtable_t pte)
@@ -117,6 +117,6 @@ static inline void check_pgt_cache(void)
        quicklist_trim(0, NULL, 25, 16);
 }
 
-#define __pte_free_tlb(tlb, pte      pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, address)      pte_free((tlb)->mm, pte)
 
 #endif                         /* _ASM_IA64_PGALLOC_H */
index ae6922626bf49bbecae323b08e58478bcaeb4e07..8ce2e388e37c550573bfc2ca28033a43b7d74d50 100644 (file)
@@ -48,7 +48,7 @@ struct thread_info {
        .flags          = 0,                    \
        .cpu            = 0,                    \
        .addr_limit     = KERNEL_DS,            \
-       .preempt_count  = 0,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 20d8a39680c212af2e455327fb5782680af8c772..85d965cb19a0835ace573551d667053fcc8fa260 100644 (file)
@@ -236,22 +236,22 @@ do {                                                      \
        __tlb_remove_tlb_entry(tlb, ptep, addr);        \
 } while (0)
 
-#define pte_free_tlb(tlb, ptep)                                \
+#define pte_free_tlb(tlb, ptep, address)               \
 do {                                                   \
        tlb->need_flush = 1;                            \
-       __pte_free_tlb(tlb, ptep);                      \
+       __pte_free_tlb(tlb, ptep, address);             \
 } while (0)
 
-#define pmd_free_tlb(tlb, ptep)                                \
+#define pmd_free_tlb(tlb, ptep, address)               \
 do {                                                   \
        tlb->need_flush = 1;                            \
-       __pmd_free_tlb(tlb, ptep);                      \
+       __pmd_free_tlb(tlb, ptep, address);             \
 } while (0)
 
-#define pud_free_tlb(tlb, pudp)                                \
+#define pud_free_tlb(tlb, pudp, address)               \
 do {                                                   \
        tlb->need_flush = 1;                            \
-       __pud_free_tlb(tlb, pudp);                      \
+       __pud_free_tlb(tlb, pudp, address);             \
 } while (0)
 
 #endif /* _ASM_IA64_TLB_H */
index e425227a418e9b15a40a0dce0d8f09be3061ec90..88afb54501e48feba6c24d6f25c7f5967b308c89 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef _ASM_IA64_XEN_HYPERVISOR_H
 #define _ASM_IA64_XEN_HYPERVISOR_H
 
+#include <linux/err.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>     /* to compile feature.c */
 #include <xen/features.h>              /* to comiple xen-netfront.c */
index 086a2aeb0404e6a889d6b10cfe766eca20a568c3..39a3cd0a417326be10680e9d9cb52458e400051f 100644 (file)
@@ -6,6 +6,14 @@ int iommu_detected __read_mostly;
 struct dma_map_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+}
+fs_initcall(dma_init);
+
 struct dma_map_ops *dma_get_ops(struct device *dev)
 {
        return dma_ops;
index 92c9689b7d9764a80fc72b8a06f2c45b10443387..9daa87fdb0182e63cde61e6c78df1ff6dea41340 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
-#include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
index f11a2b909cdbf8ab3bc1a11195b0160173c2a58b..0fc7361989797d9a8c6fb6cc2a823367f75236e0 100644 (file)
@@ -58,7 +58,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -68,7 +68,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 
 #define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
 #define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb, x)         do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr)   do { } while (0)
 #define pgd_populate(mm, pmd, pte)     BUG()
 
 #define check_pgt_cache()      do { } while (0)
index 8589d462df27e366863974619b5cf293e0b9213c..07bb5bd00e2a0660dc3be6c0c0c4514da8ade81b 100644 (file)
@@ -57,8 +57,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -68,7 +66,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index bf0abe9e1f73e9bc9f30b1162df1577f75f51907..98b8feb12ed899e6dba32d0532b981057d4f5a6e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index d08bf6261df88889f0e39091f8356580920208bb..15ee4c74a9f0621c6ca4d45380e6267475edf8e5 100644 (file)
@@ -54,7 +54,8 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t page)
        __free_page(page);
 }
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page)
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
+                                 unsigned long address)
 {
        pgtable_page_dtor(page);
        cache_page(kmap(page));
@@ -73,7 +74,8 @@ static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
        return free_pointer_table(pmd);
 }
 
-static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+                                unsigned long address)
 {
        return free_pointer_table(pmd);
 }
index d4c83f14381652402d35f4b3cb5fb5967f97a6de..48d80d5a666f80b64d5b62e318197b1752e29733 100644 (file)
@@ -32,7 +32,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t page)
         __free_page(page);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,addr)                   \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), pte);                    \
@@ -80,7 +80,7 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page
  * inside the pgd, so has no extra memory associated with it.
  */
 #define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb, x)         do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr)   do { } while (0)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
index af0fda46e94bc969978a9572221ac2843f23bae2..6ea5c33b3c564ed2d1558840f9642241fcc2e2e8 100644 (file)
@@ -19,6 +19,7 @@ struct thread_info {
 {                                              \
        .task           = &tsk,                 \
        .exec_domain    = &default_exec_domain, \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 82529f424ea3d567d0c1a9a2991b9591f7dacd85..c2bde5e24b0b9063d3c984e55dc168a6d9329158 100644 (file)
@@ -49,6 +49,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index d0bcf80a113659d2b3da42e9cd0e7c4c58f701a9..8439598d4655bb8192c79f696b60ac2d1ea05a2d 100644 (file)
@@ -6,14 +6,16 @@ endif
 
 # What CPU vesion are we building for, and crack it open
 # as major.minor.rev
-CPU_VER=$(subst ",,$(CONFIG_XILINX_MICROBLAZE0_HW_VER) )
-CPU_MAJOR=$(shell echo $(CPU_VER) | cut -d '.' -f 1)
-CPU_MINOR=$(shell echo $(CPU_VER) | cut -d '.' -f 2)
-CPU_REV=$(shell echo $(CPU_VER) | cut -d '.' -f 3)
+CPU_VER   := $(shell echo $(CONFIG_XILINX_MICROBLAZE0_HW_VER))
+CPU_MAJOR := $(shell echo $(CPU_VER) | cut -d '.' -f 1)
+CPU_MINOR := $(shell echo $(CPU_VER) | cut -d '.' -f 2)
+CPU_REV   := $(shell echo $(CPU_VER) | cut -d '.' -f 3)
 
 export CPU_VER CPU_MAJOR CPU_MINOR CPU_REV
 
 # Use cpu-related CONFIG_ vars to set compile options.
+# The various CONFIG_XILINX cpu features options are integers 0/1/2...
+# rather than bools y/n
 
 # Work out HW multipler support.  This is icky.
 # 1. Spartan2 has no HW multiplers.
@@ -34,30 +36,29 @@ CPUFLAGS-$(CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR) += -mxl-pattern-compare
 
 CPUFLAGS-1 += $(call cc-option,-mcpu=v$(CPU_VER))
 
-# The various CONFIG_XILINX cpu features options are integers 0/1/2...
-# rather than bools y/n
-
 # r31 holds current when in kernel mode
-CFLAGS_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
+KBUILD_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
 
 LDFLAGS                :=
 LDFLAGS_vmlinux        :=
-LDFLAGS_BLOB := --format binary --oformat elf32-microblaze
 
-LIBGCC := $(shell $(CC) $(CFLAGS_KERNEL) -print-libgcc-file-name)
+LIBGCC := $(shell $(CC) $(KBUILD_KERNEL) -print-libgcc-file-name)
 
-head-y         := arch/microblaze/kernel/head.o
-libs-y         += arch/microblaze/lib/ $(LIBGCC)
-core-y         += arch/microblaze/kernel/ arch/microblaze/mm/ \
-                  arch/microblaze/platform/
+head-y := arch/microblaze/kernel/head.o
+libs-y += arch/microblaze/lib/
+libs-y += $(LIBGCC)
+core-y += arch/microblaze/kernel/
+core-y += arch/microblaze/mm/
+core-y += arch/microblaze/platform/
 
-boot := arch/$(ARCH)/boot
+boot := arch/microblaze/boot
 
 # defines filename extension depending memory management type
 ifeq ($(CONFIG_MMU),)
-MMUEXT         := -nommu
+MMU := -nommu
 endif
-export MMUEXT
+
+export MMU
 
 all: linux.bin
 
index 5c173424d0744bdd6cfdda945e57985adff9060c..7c3ec13b44d860c8180a3bc15460e1dbeec7886c 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/byteorder.h>
 #include <asm/page.h>
 #include <linux/types.h>
-#include <asm/byteorder.h>
 #include <linux/mm.h>          /* Get struct page {...} */
 
 
index 59a757e46ba552ad57736103ea42c3378e83af90..b0131da1387bb131cd9e7666519eedb9591302e3 100644 (file)
@@ -180,7 +180,7 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
        __free_page(ptepage);
 }
 
-#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
 
 #define pmd_populate(mm, pmd, pte)     (pmd_val(*(pmd)) = page_address(pte))
 
@@ -193,7 +193,7 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
  */
 #define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
 /*#define pmd_free(mm, x)                      do { } while (0)*/
-#define __pmd_free_tlb(tlb, x)         do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr)   do { } while (0)
 #define pgd_populate(mm, pmd, pte)     BUG()
 
 extern int do_check_pgt_cache(int, int);
index 4c57a586a989e6695be8b14a2337d34f87f7f751..cc3a4dfc3eaa94c75dcc37f396a52b8edc373086 100644 (file)
@@ -185,6 +185,7 @@ static inline pte_t pte_mkspecial(pte_t pte)        { return pte; }
 
 /* Definitions for MicroBlaze. */
 #define        _PAGE_GUARDED   0x001   /* G: page is guarded from prefetch */
+#define _PAGE_FILE     0x001   /* when !present: nonlinear file mapping */
 #define _PAGE_PRESENT  0x002   /* software: PTE contains a translation */
 #define        _PAGE_NO_CACHE  0x004   /* I: caching is inhibited */
 #define        _PAGE_WRITETHRU 0x008   /* W: caching is write-through */
@@ -320,8 +321,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
 static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC; }
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-/* FIXME */
-static inline int pte_file(pte_t pte)          { return 0; }
+static inline int pte_file(pte_t pte)  { return pte_val(pte) & _PAGE_FILE; }
 
 static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -488,7 +488,7 @@ static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
 /* Encode and decode a nonlinear file mapping entry */
 #define PTE_FILE_MAX_BITS      29
 #define pte_to_pgoff(pte)      (pte_val(pte) >> 3)
-#define pgoff_to_pte(off)      ((pte_t) { ((off) << 3) })
+#define pgoff_to_pte(off)      ((pte_t) { ((off) << 3) | _PAGE_FILE })
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
index 20f7b3a926e850ca5d621265d5933eb26359fad4..37e6f305a68ee161c8cf170b162b7de39cadf1a1 100644 (file)
 #define _ASM_MICROBLAZE_PROM_H
 #ifdef __KERNEL__
 
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER           0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE       0x1 /* Start of node, full name */
+#define OF_DT_END_NODE         0x2 /* End node */
+#define OF_DT_PROP             0x3 /* Property: name off, size, content */
+#define OF_DT_NOP              0x4 /* nop */
+#define OF_DT_END              0x9
+
+#define OF_DT_VERSION          0x10
+
+#ifndef __ASSEMBLY__
+
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
 #define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
 #define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
 
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER           0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE       0x1 /* Start of node, full name */
-#define OF_DT_END_NODE         0x2 /* End node */
-#define OF_DT_PROP             0x3 /* Property: name off, size, content */
-#define OF_DT_NOP              0x4 /* nop */
-#define OF_DT_END              0x9
-
-#define OF_DT_VERSION          0x10
-
 /*
  * This is what gets passed to the kernel by prom_init or kexec
  *
@@ -309,5 +311,6 @@ extern void __iomem *of_iomap(struct device_node *device, int index);
  */
 #include <linux/of.h>
 
+#endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_PROM_H */
index 7fac44498445f82595431e75c28fcf61a6731e21..6e92885d381a80ee3adc680632415c3911ecdb64 100644 (file)
@@ -75,8 +75,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
@@ -84,7 +82,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index c472d280113285780afb447948ff543bb6a57fd9..e8abd4a0349c381f45d1daeb7972db0235fd3e12 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _ASM_MICROBLAZE_TLB_H
 #define _ASM_MICROBLAZE_TLB_H
 
-#define tlb_flush(tlb) do {} while (0)
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
 
 #include <asm-generic/tlb.h>
 
index 65adad61e7e90b4bbf05cc161caaf4a6a6757290..5431b4631a7ad479bc23baf72de4563c68b8efb8 100644 (file)
@@ -189,7 +189,7 @@ extern long strnlen_user(const char *src, long count);
 
 #define __put_user(x, ptr)                                             \
 ({                                                                     \
-       __typeof__(*(ptr)) __gu_val = x;                                \
+       __typeof__(*(ptr)) volatile __gu_val = (x);                     \
        long __gu_err = 0;                                              \
        switch (sizeof(__gu_val)) {                                     \
        case 1:                                                         \
index f4a5e19a20eb98f6848e01f3d2708d8e105446b2..d487729683de8a0b66c6d082a8cefb096621687d 100644 (file)
@@ -17,4 +17,4 @@ obj-$(CONFIG_HEART_BEAT)      += heartbeat.o
 obj-$(CONFIG_MODULES)          += microblaze_ksyms.o module.o
 obj-$(CONFIG_MMU)              += misc.o
 
-obj-y  += entry$(MMUEXT).o
+obj-y  += entry$(MMU).o
index 153f57c57b6d90ef008d706b4e34319f14045949..c259786e7faa1c51853d3a0e31621ea1ddd154c7 100644 (file)
@@ -22,7 +22,7 @@
 
 #define CI(c, p) { ci->c = PVR_##p(pvr); }
 #define err_printk(x) \
-       early_printk("ERROR: Microblaze " x " - different for PVR and DTS\n");
+       early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
 
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 {
index 450ca6bb828db34ae43b3a1d35a6a16ef265c4f5..adb448f93d5fd3157c89b2336ca52488da6ecb42 100644 (file)
@@ -18,7 +18,7 @@ static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
 static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
 
 #define err_printk(x) \
-       early_printk("ERROR: Microblaze " x "- different for kernel and DTS\n");
+       early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n");
 
 void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
 {
index a10bea119b946f0b637befe039705c432cdce888..c411c6757deb845a984ae734e108fa216ceb18c0 100644 (file)
@@ -26,6 +26,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"7.10.b", 0x09},
        {"7.10.c", 0x0a},
        {"7.10.d", 0x0b},
+       {"7.20.a", 0x0c},
+       {"7.20.b", 0x0d},
        /* FIXME There is no keycode defined in MBV for these versions */
        {"2.10.a", 0x10},
        {"3.00.a", 0x20},
index e568d6ec621bfa400bc5b506b9ff6afbe327c002..e41c6ce2a7be3e50589e48e7f661852afabd7709 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/page.h>
+#include <asm/prom.h>          /* for OF_DT_HEADER */
 
 #ifdef CONFIG_MMU
 #include <asm/setup.h> /* COMMAND_LINE_SIZE */
@@ -54,11 +55,19 @@ ENTRY(_start)
        andi    r1, r1, ~2
        mts     rmsr, r1
 
-/* save fdt to kernel location */
-/* r7 stores pointer to fdt blob */
-       beqi    r7, no_fdt_arg
+/* r7 may point to an FDT, or there may be one linked in.
+   if it's in r7, we've got to save it away ASAP.
+   We ensure r7 points to a valid FDT, just in case the bootloader
+   is broken or non-existent */
+       beqi    r7, no_fdt_arg                  /* NULL pointer?  don't copy */
+       lw      r11, r0, r7                     /* Does r7 point to a */
+       rsubi   r11, r11, OF_DT_HEADER          /* valid FDT? */
+       beqi    r11, _prepare_copy_fdt
+       or      r7, r0, r0              /* clear R7 when not valid DTB */
+       bnei    r11, no_fdt_arg                 /* No - get out of here */
+_prepare_copy_fdt:
        or      r11, r0, r0 /* incremment */
-       ori     r4, r0, TOPHYS(_fdt_start) /* save bram context */
+       ori     r4, r0, TOPHYS(_fdt_start)
        ori     r3, r0, (0x4000 - 4)
 _copy_fdt:
        lw      r12, r7, r11 /* r12 = r7 + r11 */
index 9d591cd74fc221293fa1d647f530c0e29120dbe4..3288c9737671adc6362ba6a079a717d342fa487a 100644 (file)
@@ -74,6 +74,7 @@
 
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
+#include <asm/signal.h>
 #include <asm/asm-offsets.h>
 
 /* Helpful Macros */
@@ -428,19 +429,9 @@ handle_unaligned_ex:
        mfs     r17, rbtr;      /* ESR[DS] set - return address in BTR */
        nop
 _no_delayslot:
-#endif
-
-#ifdef CONFIG_MMU
-       /* Check if unaligned address is last on a 4k page */
-               andi    r5, r4, 0xffc
-               xori    r5, r5, 0xffc
-               bnei    r5, _unaligned_ex2
-       _unaligned_ex1:
-               RESTORE_STATE;
-/* Another page must be accessed or physical address not in page table */
-               bri     unaligned_data_trap
-
-       _unaligned_ex2:
+       /* jump to high level unaligned handler */
+       RESTORE_STATE;
+       bri     unaligned_data_trap
 #endif
        andi    r6, r3, 0x3E0; /* Mask and extract the register operand */
        srl     r6, r6; /* r6 >> 5 */
@@ -450,45 +441,6 @@ _no_delayslot:
        srl     r6, r6;
        /* Store the register operand in a temporary location */
        sbi     r6, r0, TOPHYS(ex_reg_op);
-#ifdef CONFIG_MMU
-       /* Get physical address */
-       /* If we are faulting a kernel address, we have to use the
-        * kernel page tables.
-        */
-       ori     r5, r0, CONFIG_KERNEL_START
-       cmpu    r5, r4, r5
-       bgti    r5, _unaligned_ex3
-       ori     r5, r0, swapper_pg_dir
-       bri     _unaligned_ex4
-
-       /* Get the PGD for the current thread. */
-_unaligned_ex3: /* user thread */
-       addi    r5 ,CURRENT_TASK, TOPHYS(0); /* get current task address */
-       lwi     r5, r5, TASK_THREAD + PGDIR
-_unaligned_ex4:
-       tophys(r5,r5)
-       BSRLI(r6,r4,20)                 /* Create L1 (pgdir/pmd) address */
-       andi    r6, r6, 0xffc
-/* Assume pgdir aligned on 4K boundary, no need for "andi r5,r5,0xfffff003" */
-       or      r5, r5, r6
-       lwi     r6, r5, 0               /* Get L1 entry */
-       andi    r5, r6, 0xfffff000      /* Extract L2 (pte) base address. */
-       beqi    r5, _unaligned_ex1      /* Bail if no table */
-
-       tophys(r5,r5)
-       BSRLI(r6,r4,10)                 /* Compute PTE address */
-       andi    r6, r6, 0xffc
-       andi    r5, r5, 0xfffff003
-       or      r5, r5, r6
-       lwi     r5, r5, 0               /* Get Linux PTE */
-
-       andi    r6, r5, _PAGE_PRESENT
-       beqi    r6, _unaligned_ex1      /* Bail if no page */
-
-       andi    r5, r5, 0xfffff000      /* Extract RPN */
-       andi    r4, r4, 0x00000fff      /* Extract offset */
-       or      r4, r4, r5              /* Create physical address */
-#endif /* CONFIG_MMU */
 
        andi    r6, r3, 0x400; /* Extract ESR[S] */
        bnei    r6, ex_sw;
@@ -959,15 +911,15 @@ _unaligned_data_exception:
        andi    r6, r3, 0x800;  /* Extract ESR[W] - delay slot */
 ex_lw_vm:
        beqid   r6, ex_lhw_vm;
-       lbui    r5, r4, 0;      /* Exception address in r4 - delay slot */
+load1: lbui    r5, r4, 0;      /* Exception address in r4 - delay slot */
 /* Load a word, byte-by-byte from destination address and save it in tmp space*/
        la      r6, r0, ex_tmp_data_loc_0;
        sbi     r5, r6, 0;
-       lbui    r5, r4, 1;
+load2: lbui    r5, r4, 1;
        sbi     r5, r6, 1;
-       lbui    r5, r4, 2;
+load3: lbui    r5, r4, 2;
        sbi     r5, r6, 2;
-       lbui    r5, r4, 3;
+load4: lbui    r5, r4, 3;
        sbi     r5, r6, 3;
        brid    ex_lw_tail_vm;
 /* Get the destination register value into r3 - delay slot */
@@ -977,7 +929,7 @@ ex_lhw_vm:
         * save it in tmp space */
        la      r6, r0, ex_tmp_data_loc_0;
        sbi     r5, r6, 0;
-       lbui    r5, r4, 1;
+load5: lbui    r5, r4, 1;
        sbi     r5, r6, 1;
        lhui    r3, r6, 0;      /* Get the destination register value into r3 */
 ex_lw_tail_vm:
@@ -996,22 +948,53 @@ ex_sw_tail_vm:
        swi     r3, r5, 0;      /* Get the word - delay slot */
        /* Store the word, byte-by-byte into destination address */
        lbui    r3, r5, 0;
-       sbi     r3, r4, 0;
+store1:        sbi     r3, r4, 0;
        lbui    r3, r5, 1;
-       sbi     r3, r4, 1;
+store2:        sbi     r3, r4, 1;
        lbui    r3, r5, 2;
-       sbi     r3, r4, 2;
+store3:        sbi     r3, r4, 2;
        lbui    r3, r5, 3;
        brid    ret_from_exc;
-       sbi     r3, r4, 3;      /* Delay slot */
+store4:        sbi     r3, r4, 3;      /* Delay slot */
 ex_shw_vm:
        /* Store the lower half-word, byte-by-byte into destination address */
        lbui    r3, r5, 2;
-       sbi     r3, r4, 0;
+store5:        sbi     r3, r4, 0;
        lbui    r3, r5, 3;
        brid    ret_from_exc;
-       sbi     r3, r4, 1;      /* Delay slot */
+store6:        sbi     r3, r4, 1;      /* Delay slot */
 ex_sw_end_vm:                  /* Exception handling of store word, ends. */
+
+/* We have to prevent cases that get/put_user macros get unaligned pointer
+ * to bad page area. We have to find out which origin instruction caused it
+ * and called fixup for that origin instruction not instruction in unaligned
+ * handler */
+ex_unaligned_fixup:
+       ori     r5, r7, 0 /* setup pointer to pt_regs */
+       lwi     r6, r7, PT_PC; /* faulting address is one instruction above */
+       addik   r6, r6, -4 /* for finding proper fixup */
+       swi     r6, r7, PT_PC; /* a save back it to PT_PC */
+       addik   r7, r0, SIGSEGV
+       /* call bad_page_fault for finding aligned fixup, fixup address is saved
+        * in PT_PC which is used as return address from exception */
+       la      r15, r0, ret_from_exc-8 /* setup return address */
+       brid    bad_page_fault
+       nop
+
+/* We prevent all load/store because it could failed any attempt to access */
+.section __ex_table,"a";
+       .word   load1,ex_unaligned_fixup;
+       .word   load2,ex_unaligned_fixup;
+       .word   load3,ex_unaligned_fixup;
+       .word   load4,ex_unaligned_fixup;
+       .word   load5,ex_unaligned_fixup;
+       .word   store1,ex_unaligned_fixup;
+       .word   store2,ex_unaligned_fixup;
+       .word   store3,ex_unaligned_fixup;
+       .word   store4,ex_unaligned_fixup;
+       .word   store5,ex_unaligned_fixup;
+       .word   store6,ex_unaligned_fixup;
+.previous;
 .end _unaligned_data_exception
 #endif /* CONFIG_MMU */
 
index 51414171326f4bb32010585d4cef295e9de8afc4..5a45b1adfef1c91f25b191d968238c95854ee674 100644 (file)
@@ -57,7 +57,6 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
        Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
        Elf32_Sym *sym;
        unsigned long int *location;
-       unsigned long int locoffs;
        unsigned long int value;
 #if __GNUC__ < 4
        unsigned long int old_value;
@@ -113,10 +112,12 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
                        break;
 
                case R_MICROBLAZE_64_PCREL:
-                       locoffs = (location[0] & 0xFFFF) << 16 |
+#if __GNUC__ < 4
+                       old_value = (location[0] & 0xFFFF) << 16 |
                                (location[1] & 0xFFFF);
-                       value -= (unsigned long int)(location) + 4 +
-                               locoffs;
+                       value -= old_value;
+#endif
+                       value -= (unsigned long int)(location) + 4;
                        location[0] = (location[0] & 0xFFFF0000) |
                                        (value >> 16);
                        location[1] = (location[1] & 0xFFFF0000) |
@@ -125,6 +126,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
                                value);
                        break;
 
+               case R_MICROBLAZE_32_PCREL_LO:
+                       pr_debug("R_MICROBLAZE_32_PCREL_LO\n");
+                       break;
+
+               case R_MICROBLAZE_64_NONE:
+                       pr_debug("R_MICROBLAZE_NONE\n");
+                       break;
+
                case R_MICROBLAZE_NONE:
                        pr_debug("R_MICROBLAZE_NONE\n");
                        break;
@@ -133,7 +142,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
                        printk(KERN_ERR "module %s: "
                                "Unknown relocation: %u\n",
                                module->name,
-                               ELF32_R_TYPE(rela->r_info));
+                               ELF32_R_TYPE(rela[i].r_info));
                        return -ENOEXEC;
                }
        }
index b86aa623e36d053f95c61de5533782c0d92a8bb2..53ff39af6a5c0eebfcf156dd02969d231896229d 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
 
index 8709bea09604585958cd95d72c107c65d1396855..2a97bf513b64c691e81b4bd9867f537aefb6f606 100644 (file)
@@ -138,8 +138,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        setup_early_printk(NULL);
 #endif
 
-       early_printk("Ramdisk addr 0x%08x, FDT 0x%08x\n", ram, fdt);
-       printk(KERN_NOTICE "Found FDT at 0x%08x\n", fdt);
+       early_printk("Ramdisk addr 0x%08x, ", ram);
+       if (fdt)
+               early_printk("FDT at 0x%08x\n", fdt);
+       else
+               early_printk("Compiled-in FDT at 0x%08x\n",
+                                       (unsigned int)_fdt_start);
 
 #ifdef CONFIG_MTD_UCLINUX
        early_printk("Found romfs @ 0x%08x (0x%08x)\n",
index 493819c25fbadc370bd23bcf377ad1af7fc46de1..1c80e4fc40cef1fc0513951c449452ff23139c96 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
index 8c9ebac5da10afdda17e0f4ec91f9634f20bfa1c..b96f1682bb24800d8c89316ad18007e27a45ca55 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/unistd.h>
 
 #include <asm/syscalls.h>
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly. This will be remove with new toolchain.
- */
-asmlinkage long
-sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       ret = -EINVAL;
-       switch (call) {
-       case SEMOP:
-               ret = sys_semop(first, (struct sembuf *)ptr, second);
-               break;
-       case SEMGET:
-               ret = sys_semget(first, second, third);
-               break;
-       case SEMCTL:
-       {
-               union semun fourth;
-
-               if (!ptr)
-                       break;
-               ret = (access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
-                               || (get_user(fourth.__pad, (void **)ptr)) ;
-               if (ret)
-                       break;
-               ret = sys_semctl(first, second, third, fourth);
-               break;
-       }
-       case MSGSND:
-               ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third);
-               break;
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-
-                       if (!ptr)
-                               break;
-                       ret = (access_ok(VERIFY_READ, ptr, sizeof(tmp))
-                               ? 0 : -EFAULT) || copy_from_user(&tmp,
-                               (struct ipc_kludge *) ptr, sizeof(tmp));
-                       if (ret)
-                               break;
-                       ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp,
-                                       third);
-                       break;
-                       }
-               default:
-                       ret = sys_msgrcv(first, (struct msgbuf *) ptr,
-                                       second, fifth, third);
-                       break;
-               }
-               break;
-       case MSGGET:
-               ret = sys_msgget((key_t) first, second);
-               break;
-       case MSGCTL:
-               ret = sys_msgctl(first, second, (struct msqid_ds *) ptr);
-               break;
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = access_ok(VERIFY_WRITE, (ulong *) third,
-                                       sizeof(ulong)) ? 0 : -EFAULT;
-                       if (ret)
-                               break;
-                       ret = do_shmat(first, (char *) ptr, second, &raddr);
-                       if (ret)
-                               break;
-                       ret = put_user(raddr, (ulong *) third);
-                       break;
-                       }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               break;
-                       ret = do_shmat(first, (char *) ptr, second,
-                                       (ulong *) third);
-                       break;
-               }
-               break;
-       case SHMDT:
-               ret = sys_shmdt((char *)ptr);
-               break;
-       case SHMGET:
-               ret = sys_shmget(first, second, third);
-               break;
-       case SHMCTL:
-               ret = sys_shmctl(first, second, (struct shmid_ds *) ptr);
-               break;
-       }
-       return ret;
-}
 
 asmlinkage long microblaze_vfork(struct pt_regs *regs)
 {
index 31b32a6c5f4ee06a39c3defa757c27a8f13c5b5d..216db817beb6a2933a8b2b0973a92d2de9e874d5 100644 (file)
@@ -121,7 +121,7 @@ ENTRY(sys_call_table)
        .long sys_wait4
        .long sys_swapoff               /* 115 */
        .long sys_sysinfo
-       .long sys_ipc
+       .long sys_ni_syscall            /* old sys_ipc */
        .long sys_fsync
        .long sys_ni_syscall            /* sys_sigreturn_wrapper */
        .long sys_clone         /* 120 */
index 956607a63f4c21327b1b1d749031cbbd7510ee58..d9d249a66ff2eda43688483cb1cab0aba3434de9 100644 (file)
@@ -69,7 +69,7 @@ static int store_updates_sp(struct pt_regs *regs)
  * It is called from do_page_fault above and from some of the procedures
  * in traps.c.
  */
-static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 {
        const struct exception_table_entry *fixup;
 /* MS: no context */
@@ -122,15 +122,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
        }
 #endif /* CONFIG_KGDB */
 
-       if (in_atomic() || mm == NULL) {
-               /* FIXME */
-               if (kernel_mode(regs)) {
-                       printk(KERN_EMERG
-                               "Page fault in kernel mode - Oooou!!! pid %d\n",
-                               current->pid);
-                       _exception(SIGSEGV, regs, code, address);
-                       return;
-               }
+       if (in_atomic() || !mm) {
+               if (kernel_mode(regs))
+                       goto bad_area_nosemaphore;
+
                /* in_atomic() in user mode is really bad,
                   as is current->mm == NULL. */
                printk(KERN_EMERG "Page fault in user mode with "
index 1275831dda29b65ae90d2046f781a747cb4a3df0..3738f4b48cbd63b75b9b91095c6ef9807f26866d 100644 (file)
@@ -98,23 +98,12 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_pages(pte, PTE_ORDER);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,address)                        \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), pte);                    \
 } while (0)
 
-#ifdef CONFIG_32BIT
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb, x)         do { } while (0)
-
-#endif
-
 #ifdef CONFIG_64BIT
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -132,7 +121,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
-#define __pmd_free_tlb(tlb, x) pmd_free((tlb)->mm, x)
+#define __pmd_free_tlb(tlb, x, addr)   pmd_free((tlb)->mm, x)
 
 #endif
 
index 143a48136a4b0f7e599adf1ce41d2bea290a7777..f9df720d2e40e215aa0cb21561f467d6d95a2b6b 100644 (file)
@@ -39,8 +39,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
@@ -48,7 +46,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = _TIF_FIXADE,          \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
index c4f9ac17474a2157d7a6ab12e0c485cd61b11c48..32644b4a07144979be8d1466ad639787abcf795d 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
 
index 471c09aa1614ae4aebe0b3d4143cef29e9bd52e9..8c2834f5919da563a06a861206cf37164b06615c 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
index ec057e1bd4cf3e72538d4b8c5ae3a83b4c887694..a19f11327cd87ce9dd2c578c1ecf25bf655d083f 100644 (file)
@@ -51,6 +51,6 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte)
 }
 
 
-#define __pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte))
+#define __pte_free_tlb(tlb, pte, addr) tlb_remove_page((tlb), (pte))
 
 #endif /* _ASM_PGALLOC_H */
index 78a3881f3c1250f39eea83dc80a320c826ed650d..58d64f8b2cc3d44769ecdcee23c3ccb9477a4239 100644 (file)
@@ -65,8 +65,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -76,7 +74,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index e143339ad28e00869d9b23c1d882d994cdd89d62..cf847dabc1bd3a7cd810628ea2500bbfd8b922a7 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 9f7572a0f5784a30d9ff16bbcfa407d10fc8a066..feb2f2e810db7c785ea5a7562ac77dfb79666a79 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
index bca5a84dc72cced1e6c597a02ec725181a651cfb..3e52a105432791ccab5860dac6fbc4f2b0436db1 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -21,7 +20,6 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
-#include <linux/syscalls.h>
 #include <linux/tty.h>
 
 #include <asm/uaccess.h>
index 0dfdc500112411333ad61911ac49beb7b2aac31a..91365adba4f5568925d3398545d3b9bcc9ed9f96 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
index c96ba3da95ac15b6b2582fae648925179e2d9d6b..f4aa079346543f4ecfc47388bec429c66cf35733 100644 (file)
@@ -107,7 +107,7 @@ SECTIONS
   __init_end = .;
   /* freed after init ends here */
 
-  BSS(4)
+  BSS_SECTION(0, PAGE_SIZE, 4)
 
   _end = . ;
 
index a62e1e138bc101c112872eae8b4eb9e0ce61d8cf..53bb17d0f0687764ab1d8a4e05d6cdfc81c03e25 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>             /* For unblank_screen() */
index 94c4a43580657a74b594561180759b5d2b43c37c..30016251f658507ec5a6501c35028dd74be22716 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
index 0407959da489d54a72b4ccab371cc21e996e79a3..4ce0edfbe9694dc4daaed2253a625e9d46a25c72 100644 (file)
@@ -23,7 +23,7 @@ struct thread_info {
        .flags          = 0,                    \
        .cpu            = 0,                    \
        .addr_limit     = KERNEL_DS,            \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall     \
        }                                       \
index 383b1db310ee71e18789112587f9ba3e818bdd25..07924903989eed2a8ce2d93cb349332918e1db6e 100644 (file)
@@ -21,7 +21,7 @@ do {  if (!(tlb)->fullmm)     \
 
 #include <asm-generic/tlb.h>
 
-#define __pmd_free_tlb(tlb, pmd)       pmd_free((tlb)->mm, pmd)
-#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
 
 #endif
index 0815eb40acae214b8947a4da26d565bfaf4fb8a7..c9500d666a1de37687346d7b7cfae5dd2f81ac7a 100644 (file)
@@ -16,7 +16,7 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
  */
 /* #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); }) */
 #define pmd_free(mm, x)                do { } while (0)
-#define __pmd_free_tlb(tlb,x)          do { } while (0)
+#define __pmd_free_tlb(tlb,x,a)                do { } while (0)
 /* #define pgd_populate(mm, pmd, pte)      BUG() */
 
 #ifndef CONFIG_BOOKE
index afda2bdd860f8bc8eb20dbb915701fface743ce6..e6f069c4f713a7b2c7ce76e3da593693d2fc1d79 100644 (file)
@@ -118,11 +118,11 @@ static inline void pgtable_free(pgtable_free_t pgf)
                kmem_cache_free(pgtable_cache[cachenum], p);
 }
 
-#define __pmd_free_tlb(tlb, pmd)       \
+#define __pmd_free_tlb(tlb, pmd,addr)                \
        pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
                PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
 #ifndef CONFIG_PPC_64K_PAGES
-#define __pud_free_tlb(tlb, pud)       \
+#define __pud_free_tlb(tlb, pud, addr)               \
        pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
                PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
 #endif /* CONFIG_PPC_64K_PAGES */
index 5d8480265a77561bfa48cb2b82eb2fca9b4a4fd2..1730e5e298d61b07df858de4e32078c7ff4201e4 100644 (file)
@@ -38,14 +38,14 @@ static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
 extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
 
 #ifdef CONFIG_SMP
-#define __pte_free_tlb(tlb,ptepage)    \
+#define __pte_free_tlb(tlb,ptepage,address)            \
 do { \
        pgtable_page_dtor(ptepage); \
        pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-               PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
+                                       PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
 } while (0)
 #else
-#define __pte_free_tlb(tlb, pte      pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, address)      pte_free((tlb)->mm, (pte))
 #endif
 
 
index 9aba5a38a7c4f32a011c6af5c3bd22e28e88d8a6..c8b329255678802bc34e27c85e84bf5338be25ea 100644 (file)
@@ -46,15 +46,13 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                  \
 {                                              \
        .task =         &tsk,                   \
        .exec_domain =  &default_exec_domain,   \
        .cpu =          0,                      \
-       .preempt_count = 1,                     \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 5d755ef7ac8f21d97fbe5ef347b38c44a0f17e23..5a9f5cbd40a48e9c19c4afaae64e86a57fd5c18d 100644 (file)
@@ -358,6 +358,7 @@ static struct power_pmu power7_pmu = {
        .get_constraint         = power7_get_constraint,
        .get_alternatives       = power7_get_alternatives,
        .disable_pmc            = power7_disable_pmc,
+       .flags                  = PPMU_ALT_SIPR,
        .n_generic              = ARRAY_SIZE(power7_generic_events),
        .generic_events         = power7_generic_events,
        .cache_events           = &power7_cache_events,
index 9fa2c7dcd05a4501034395e6f587523cffb969d0..ef149880c145bf5d0ac639e87ba57c094b86bf51 100644 (file)
@@ -736,15 +736,16 @@ void user_disable_single_step(struct task_struct *task)
 {
        struct pt_regs *regs = task->thread.regs;
 
-
-#if defined(CONFIG_BOOKE)
-       /* If DAC then do not single step, skip */
-       if (task->thread.dabr)
-               return;
-#endif
-
        if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
+               /* If DAC don't clear DBCRO_IDM or MSR_DE */
+               if (task->thread.dabr)
+                       task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT);
+               else {
+                       task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
+                       regs->msr &= ~MSR_DE;
+               }
+#elif defined(CONFIG_40x)
                task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
                regs->msr &= ~MSR_DE;
 #else
index 297632cba047e5ee980950059bee841217978631..8a6daf4129f67ffb143e762a3972a1419b30d0bd 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/regset.h>
index ef36cbbc5882281ccb26ca2c0b4fd14bf23a06d3..ea4d64644d029a283fe17e379d03be319d845b2e 100644 (file)
@@ -80,10 +80,10 @@ _GLOBAL(load_up_altivec)
        mtvscr  vr0
        REST_32VRS(0,r4,r5)
 #ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
+       /* Update last_task_used_altivec to 'current' */
        subi    r4,r5,THREAD            /* Back to 'current' */
        fromreal(r4)
-       PPC_STL r4,ADDROFF(last_task_used_math)(r3)
+       PPC_STL r4,ADDROFF(last_task_used_altivec)(r3)
 #endif /* CONFIG_SMP */
        /* restore registers and return */
        blr
@@ -172,7 +172,7 @@ _GLOBAL(load_up_vsx)
        oris    r12,r12,MSR_VSX@h
        std     r12,_MSR(r1)
 #ifndef CONFIG_SMP
-       /* Update last_task_used_math to 'current' */
+       /* Update last_task_used_vsx to 'current' */
        ld      r4,PACACURRENT(r13)
        std     r4,0(r3)
 #endif /* CONFIG_SMP */
index 9920d6a7cf290cc02339da13d337fa6eddbf021a..c46ef2ffa3d95673febbbe9be0d167a5879ec04f 100644 (file)
@@ -305,7 +305,7 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
 
        pmd = pmd_offset(pud, start);
        pud_clear(pud);
-       pmd_free_tlb(tlb, pmd);
+       pmd_free_tlb(tlb, pmd, start);
 }
 
 static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
@@ -348,7 +348,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
 
        pud = pud_offset(pgd, start);
        pgd_clear(pgd);
-       pud_free_tlb(tlb, pud);
+       pud_free_tlb(tlb, pud, start);
 }
 
 /*
index e577839f3073e5a6e5687193817ddcb6e354c423..2ae5d72f47edaad3198a030c0ee7ed09deeea6b8 100644 (file)
@@ -95,6 +95,11 @@ config S390
        select HAVE_ARCH_TRACEHOOK
        select INIT_ALL_POSSIBLE
        select HAVE_PERF_COUNTERS
+       select GENERIC_ATOMIC64 if !64BIT
+
+config SCHED_OMIT_FRAME_POINTER
+       bool
+       default y
 
 source "init/Kconfig"
 
@@ -116,6 +121,9 @@ config 32BIT
        bool
        default y if !64BIT
 
+config KTIME_SCALAR
+       def_bool 32BIT
+
 config SMP
        bool "Symmetric multi-processing support"
        ---help---
index fca9dffcc669b186f779785ae8d1ac3a9858c356..c7d0abfb0f0089a9ed9b716a31928c563abc18e2 100644 (file)
@@ -268,7 +268,12 @@ static __inline__ int atomic64_add_unless(atomic64_t *v,
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
 #undef __CSG_LOOP
-#endif
+
+#else /* __s390x__ */
+
+#include <asm-generic/atomic64.h>
+
+#endif /* __s390x__ */
 
 #define smp_mb__before_atomic_dec()    smp_mb()
 #define smp_mb__after_atomic_dec()     smp_mb()
index a7205a3828cb1553b89bb6730263c6549f26fbb9..7015188c2cc275b5cb86ad4ee1d4e326239f9fcc 100644 (file)
@@ -6,3 +6,5 @@
 
 static inline void set_perf_counter_pending(void) {}
 static inline void clear_perf_counter_pending(void) {}
+
+#define PERF_COUNTER_INDEX_OFFSET 0
index 925bcc6490354c3f2fa2c5dbbca8b37b553b1bd6..ba1cab9fc1f92cd19acfe34d2353cce8a0858c7e 100644 (file)
@@ -61,7 +61,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index 3d8a96d39d9d6a9a999c0f493911af00e204b605..81150b0536890b7d664052a33f22d397bb05b852 100644 (file)
@@ -96,7 +96,8 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
  * pte_free_tlb frees a pte table and clears the CRSTE for the
  * page table from the tlb.
  */
-static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte)
+static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+                               unsigned long address)
 {
        if (!tlb->fullmm) {
                tlb->array[tlb->nr_ptes++] = pte;
@@ -113,7 +114,8 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte)
  * as the pgd. pmd_free_tlb checks the asce_limit against 2GB
  * to avoid the double free of the pmd in this case.
  */
-static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+                               unsigned long address)
 {
 #ifdef __s390x__
        if (tlb->mm->context.asce_limit <= (1UL << 31))
@@ -134,7 +136,8 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
  * as the pgd. pud_free_tlb checks the asce_limit against 4TB
  * to avoid the double free of the pud in this case.
  */
-static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
+                               unsigned long address)
 {
 #ifdef __s390x__
        if (tlb->mm->context.asce_limit <= (1UL << 42))
index d2f270c995d9baefa6ac75a743c4d5d165441b57..db943a7ec51331f5f471c23f838e454eb46c99b2 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
index f9b144049dc983ef16419a415feadb14e2c0374b..8d15314381e04640bbf227ff045b9d9a782f22cf 100644 (file)
@@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void)
                machine_flags |= MACHINE_FLAG_VM;
 }
 
-static void early_pgm_check_handler(void)
+static __init void early_pgm_check_handler(void)
 {
        unsigned long addr;
        const struct exception_table_entry *fixup;
@@ -222,7 +222,7 @@ static void early_pgm_check_handler(void)
        S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 }
 
-void setup_lowcore_early(void)
+static noinline __init void setup_lowcore_early(void)
 {
        psw_t psw;
 
index b8bf4b140065226bbb8f48e3f4eadd07e8c04b7b..371a2d88f4ac7b6e170134b96b4924c69f8a8b99 100644 (file)
@@ -70,6 +70,7 @@ struct shutdown_action {
        char *name;
        void (*fn) (struct shutdown_trigger *trigger);
        int (*init) (void);
+       int init_rc;
 };
 
 static char *ipl_type_str(enum ipl_type type)
@@ -1486,11 +1487,13 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
        int i;
 
        for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
-               if (!shutdown_actions_list[i])
-                       continue;
                if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {
-                       trigger->action = shutdown_actions_list[i];
-                       return len;
+                       if (shutdown_actions_list[i]->init_rc) {
+                               return shutdown_actions_list[i]->init_rc;
+                       } else {
+                               trigger->action = shutdown_actions_list[i];
+                               return len;
+                       }
                }
        }
        return -EINVAL;
@@ -1640,8 +1643,8 @@ static void __init shutdown_actions_init(void)
        for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
                if (!shutdown_actions_list[i]->init)
                        continue;
-               if (shutdown_actions_list[i]->init())
-                       shutdown_actions_list[i] = NULL;
+               shutdown_actions_list[i]->init_rc =
+                       shutdown_actions_list[i]->init();
        }
 }
 
index 490b39934d65aa8a98cc76f5772b10f3ef9735ea..43acd73105b7f06f279776a9c96be780ae1927ce 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
index 2270730f535451f647aeea1e51abdc36ac8af542..be2cae083406206c949330ee1a267fb7136a969e 100644 (file)
@@ -687,13 +687,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE)
                lowcore->extended_save_area_addr = (u32) save_area;
-#else
-       if (vdso_alloc_per_cpu(smp_processor_id(), lowcore))
-               BUG();
 #endif
        set_prefix((u32)(unsigned long) lowcore);
        local_mcck_enable();
        local_irq_enable();
+#ifdef CONFIG_64BIT
+       if (vdso_alloc_per_cpu(smp_processor_id(), &S390_lowcore))
+               BUG();
+#endif
        for_each_possible_cpu(cpu)
                if (cpu != smp_processor_id())
                        smp_create_idle(cpu);
index 79dbfee831ec00cf05e0fef2c8b993f1da911697..49106c6e6f88336ab9e3d641e97ba25b8179df04 100644 (file)
@@ -88,10 +88,17 @@ __kernel_clock_gettime:
        llilh   %r4,0x0100
        sar     %a4,%r4
        lghi    %r4,0
+       epsw    %r5,0
        sacf    512                             /* Magic ectg instruction */
        .insn   ssf,0xc80100000000,__VDSO_ECTG_BASE(4),__VDSO_ECTG_USER(4),4
-       sacf    0
-       sar     %a4,%r2
+       tml     %r5,0x4000
+       jo      11f
+       tml     %r5,0x8000
+       jno     10f
+       sacf    256
+       j       11f
+10:    sacf    0
+11:    sar     %a4,%r2
        algr    %r1,%r0                         /* r1 = cputime as TOD value */
        mghi    %r1,1000                        /* convert to nanoseconds */
        srlg    %r1,%r1,12                      /* r1 = cputime in nanosec */
index ab6735df2d2155b2755170048701f979272e6f03..97975ec7a27471253a8da274af72d14a16e9f171 100644 (file)
@@ -3,6 +3,6 @@
 #
 
 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
-obj-$(CONFIG_32BIT) += div64.o qrnnd.o
+obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index 3f5f680726ed1e03bc74cc40a4217a93ab89e837..97c1eca83cc24274e796c491f60d5851252de150 100644 (file)
@@ -36,9 +36,11 @@ static void __udelay_disabled(unsigned long usecs)
        cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
        __ctl_load(cr0 , 0, 0);
        mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+       lockdep_off();
        trace_hardirqs_on();
        __load_psw_mask(mask);
        local_irq_disable();
+       lockdep_on();
        __ctl_load(cr0_saved, 0, 0);
        local_tick_enable(clock_saved);
        set_clock_comparator(S390_lowcore.clock_comparator);
diff --git a/arch/s390/lib/ucmpdi2.c b/arch/s390/lib/ucmpdi2.c
new file mode 100644 (file)
index 0000000..3e05ff5
--- /dev/null
@@ -0,0 +1,26 @@
+#include <linux/module.h>
+
+union ull_union {
+       unsigned long long ull;
+       struct {
+               unsigned int high;
+               unsigned int low;
+       } ui;
+};
+
+int __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+       union ull_union au = {.ull = a};
+       union ull_union bu = {.ull = b};
+
+       if (au.ui.high < bu.ui.high)
+               return 0;
+       else if (au.ui.high > bu.ui.high)
+               return 2;
+       if (au.ui.low < bu.ui.low)
+               return 0;
+       else if (au.ui.low > bu.ui.low)
+               return 2;
+       return 1;
+}
+EXPORT_SYMBOL(__ucmpdi2);
index 74eb26bf1970ee4f92bf3d6f34e3036471a6302d..e5e119fe03b2c18b0664c4ed48653889380aa7ac 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/compat.h>
 #include <linux/smp.h>
 #include <linux/kdebug.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/module.h>
index e6a4fe9f5f247154eab2ba960bf2c376ffdd9a27..bd1f5c6b0b8c57f12e96ec41f7f8f7538c222855 100644 (file)
@@ -7,24 +7,36 @@
  *
  */
 
+#include <asm/system.h>
 
-/*
- * save CPU registers before creating a hibernation image and before
- * restoring the memory state from it
- */
 void save_processor_state(void)
 {
-       /* implentation contained in the
-        * swsusp_arch_suspend function
+       /* swsusp_arch_suspend() actually saves all cpu register contents.
+        * Machine checks must be disabled since swsusp_arch_suspend() stores
+        * register contents to their lowcore save areas. That's the same
+        * place where register contents on machine checks would be saved.
+        * To avoid register corruption disable machine checks.
+        * We must also disable machine checks in the new psw mask for
+        * program checks, since swsusp_arch_suspend() may generate program
+        * checks. Disabling machine checks for all other new psw masks is
+        * just paranoia.
         */
+       local_mcck_disable();
+       /* Disable lowcore protection */
+       __ctl_clear_bit(0,28);
+       S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK;
+       S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK;
+       S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK;
+       S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK;
 }
 
-/*
- * restore the contents of CPU registers
- */
 void restore_processor_state(void)
 {
-       /* implentation contained in the
-        * swsusp_arch_resume function
-        */
+       S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK;
+       S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK;
+       S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK;
+       S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK;
+       /* Enable lowcore protection */
+       __ctl_set_bit(0,28);
+       local_mcck_enable();
 }
index 76d688da32fa3d65ee22d80041daa0baca8565bb..b26df5c5933e1d682f0dfb8f13239269b36a8bf8 100644 (file)
@@ -32,19 +32,14 @@ swsusp_arch_suspend:
        /* Deactivate DAT */
        stnsm   __SF_EMPTY(%r15),0xfb
 
-       /* Switch off lowcore protection */
-       stctg   %c0,%c0,__SF_EMPTY(%r15)
-       ni      __SF_EMPTY+4(%r15),0xef
-       lctlg   %c0,%c0,__SF_EMPTY(%r15)
-
        /* Store prefix register on stack */
        stpx    __SF_EMPTY(%r15)
 
-       /* Setup base register for lowcore (absolute 0) */
-       llgf    %r1,__SF_EMPTY(%r15)
+       /* Save prefix register contents for lowcore */
+       llgf    %r4,__SF_EMPTY(%r15)
 
        /* Get pointer to save area */
-       aghi    %r1,0x1000
+       lghi    %r1,0x1000
 
        /* Store registers */
        mvc     0x318(4,%r1),__SF_EMPTY(%r15)   /* move prefix to lowcore */
@@ -79,17 +74,15 @@ swsusp_arch_suspend:
        xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
        spx     __SF_EMPTY(%r15)
 
-       /* Setup lowcore */
-       brasl   %r14,setup_lowcore_early
+       lghi    %r2,0
+       lghi    %r3,2*PAGE_SIZE
+       lghi    %r5,2*PAGE_SIZE
+1:     mvcle   %r2,%r4,0
+       jo      1b
 
        /* Save image */
        brasl   %r14,swsusp_save
 
-       /* Switch on lowcore protection */
-       stctg   %c0,%c0,__SF_EMPTY(%r15)
-       oi      __SF_EMPTY+4(%r15),0x10
-       lctlg   %c0,%c0,__SF_EMPTY(%r15)
-
        /* Restore prefix register and return */
        lghi    %r1,0x1000
        spx     0x318(%r1)
@@ -117,11 +110,6 @@ swsusp_arch_resume:
        /* Deactivate DAT */
        stnsm   __SF_EMPTY(%r15),0xfb
 
-       /* Switch off lowcore protection */
-       stctg   %c0,%c0,__SF_EMPTY(%r15)
-       ni      __SF_EMPTY+4(%r15),0xef
-       lctlg   %c0,%c0,__SF_EMPTY(%r15)
-
        /* Set prefix page to zero */
        xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
        spx     __SF_EMPTY(%r15)
@@ -175,7 +163,7 @@ swsusp_arch_resume:
        /* Load old stack */
        lg      %r15,0x2f8(%r13)
 
-       /* Pointer to save arae */
+       /* Pointer to save area */
        lghi    %r13,0x1000
 
 #ifdef CONFIG_SMP
@@ -187,11 +175,6 @@ swsusp_arch_resume:
        /* Restore prefix register */
        spx     0x318(%r13)
 
-       /* Switch on lowcore protection */
-       stctg   %c0,%c0,__SF_EMPTY(%r15)
-       oi      __SF_EMPTY+4(%r15),0x10
-       lctlg   %c0,%c0,__SF_EMPTY(%r15)
-
        /* Activate DAT */
        stosm   __SF_EMPTY(%r15),0x04
 
index 84dd2db7104c74f4f57eb4f1c7d0bfc1f4159869..63ca37bd9a9557a27735fa1dc4c53cdb066d066a 100644 (file)
@@ -73,20 +73,12 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte,addr)                   \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb), (pte));                  \
 } while (0)
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-
-#define pmd_free(mm, x)                        do { } while (0)
-#define __pmd_free_tlb(tlb,x)          do { } while (0)
-
 static inline void check_pgt_cache(void)
 {
        quicklist_trim(QUICK_PGD, NULL, 25, 16);
index f09ac4806294007a883b0a472ed2d6654a7ef19f..d570ac2e5cb99838b486c0f65cf120ba710e20e5 100644 (file)
@@ -51,7 +51,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
index 9c16f737074afb62b552170227fdf4571c66912d..da8fe7ab87283904adac91d7fae1a7bea65af497 100644 (file)
@@ -91,9 +91,9 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 }
 
 #define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep)                pte_free((tlb)->mm, ptep)
-#define pmd_free_tlb(tlb, pmdp)                pmd_free((tlb)->mm, pmdp)
-#define pud_free_tlb(tlb, pudp)                pud_free((tlb)->mm, pudp)
+#define pte_free_tlb(tlb, ptep, addr)  pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp, addr)  pmd_free((tlb)->mm, pmdp)
+#define pud_free_tlb(tlb, pudp, addr)  pud_free((tlb)->mm, pudp)
 
 #define tlb_migrate_finish(mm)         do { } while (0)
 
index 7fbfd5a11ffae73860c64941240dff7ecbc03e51..17cb7c3adf2256b0206ea3d920578c47b9a0dbfc 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
 #include <asm/system.h>
index 681582d2696911ce7262bfa821dc1dbff5f41d94..ca2b34456c4b00c5e5854f630286e0cfe192cc96 100644 (file)
@@ -44,8 +44,8 @@ BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one, struct mm_struct *, unsigned long)
 BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *)
 #define free_pmd_fast(pmd)     BTFIXUP_CALL(free_pmd_fast)(pmd)
 
-#define pmd_free(mm, pmd)      free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
+#define pmd_free(mm, pmd)              free_pmd_fast(pmd)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
 
 BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *)
 #define pmd_populate(MM, PMD, PTE)        BTFIXUP_CALL(pmd_populate)(PMD, PTE)
@@ -62,7 +62,7 @@ BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *)
 #define pte_free_kernel(mm, pte)       BTFIXUP_CALL(free_pte_fast)(pte)
 
 BTFIXUPDEF_CALL(void, pte_free, pgtable_t )
-#define pte_free(mm, pte)      BTFIXUP_CALL(pte_free)(pte)
-#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, pte)
+#define pte_free(mm, pte)              BTFIXUP_CALL(pte_free)(pte)
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
 
 #endif /* _SPARC_PGALLOC_H */
index 0f7b0e5fb1c79ce1233437a5744a5736d6f91152..844d73a0340cd9c002a5399a10b943b8b60ce92d 100644 (file)
@@ -54,8 +54,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #define INIT_THREAD_INFO(tsk)                          \
 {                                                      \
@@ -64,7 +62,7 @@ struct thread_info {
        .exec_domain    =       &default_exec_domain,   \
        .flags          =       0,                      \
        .cpu            =       0,                      \
-       .preempt_count  =       1,                      \
+       .preempt_count  =       INIT_PREEMPT_COUNT,     \
        .restart_block  = {                             \
                .fn     =       do_no_restart_syscall,  \
        },                                              \
index 65865726b28319238b16f109a032510a14b624e5..1b45a7bbe40751a210f748759fac6c0e3fc3b879 100644 (file)
@@ -125,8 +125,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 
@@ -135,7 +133,7 @@ struct thread_info {
        .task           =       &tsk,                   \
        .flags          = ((unsigned long)ASI_P) << TI_FLAG_CURRENT_DS_SHIFT,   \
        .exec_domain    =       &default_exec_domain,   \
-       .preempt_count  =       1,                      \
+       .preempt_count  =       INIT_PREEMPT_COUNT,     \
        .restart_block  = {                             \
                .fn     =       do_no_restart_syscall,  \
        },                                              \
index ee38e731bfa635587afd73bac991fa69fad8ebec..dca406b9b6fc5b9b6400732d6abe3a9f1e9e528d 100644 (file)
@@ -100,9 +100,9 @@ static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
 }
 
 #define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp, ptepage) pte_free((mp)->mm, ptepage)
-#define pmd_free_tlb(mp, pmdp) pmd_free((mp)->mm, pmdp)
-#define pud_free_tlb(tlb,pudp) __pud_free_tlb(tlb,pudp)
+#define pte_free_tlb(mp, ptepage, addr) pte_free((mp)->mm, ptepage)
+#define pmd_free_tlb(mp, pmdp, addr) pmd_free((mp)->mm, pmdp)
+#define pud_free_tlb(tlb,pudp, addr) __pud_free_tlb(tlb,pudp,addr)
 
 #define tlb_migrate_finish(mm) do { } while (0)
 #define tlb_start_vma(tlb, vma) do { } while (0)
index 8ce6285a06d55794b7a0ea68035ba65a0b39861e..7e3dfd9bb97ed677715adc641dc530e2c0d63c9b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/signal.h>
 #include <linux/regset.h>
index a941c610e7ce0cdf8c38c38c5e3d46c32419114f..4ae91dc2feb9697c3a659aa7b993ca0636aadfb7 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/seccomp.h>
 #include <linux/audit.h>
index 5c12e79b4bdfe5ac1840e8e3fb30c911154f6476..da1218e8ee87a2beea896d93ec67401922623450 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
index 358283341b4792945036fed4e32822733dd25227..c0490c7bbde0ffd187c6f0b1838108cbf9e5cd2e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kdebug.h>
 
 #include <asm/delay.h>
index 753d128ed15885ce6143d3c167859d00a5a3627f..c28c71449a6c72652706e49cf1897c639e2f441b 100644 (file)
@@ -224,7 +224,12 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        if (!strcmp(type, "domain-services-port"))
                bus_id_name = "ds";
 
-       if (strlen(bus_id_name) >= BUS_ID_SIZE - 4) {
+       /*
+        * 20 char is the old driver-core name size limit, which is no more.
+        * This check can probably be removed after review and possible
+        * adaption of the vio users name length handling.
+        */
+       if (strlen(bus_id_name) >= 20 - 4) {
                printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
                       bus_id_name);
                return NULL;
index 718984359f8c8876d84a2a902fa0b6fa6b4cb933..32c8ce4e15153ee6d42fb72fd7579df0400f9e69 100644 (file)
@@ -40,7 +40,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb,pte)                                \
+#define __pte_free_tlb(tlb,pte, address)               \
 do {                                                   \
        pgtable_page_dtor(pte);                         \
        tlb_remove_page((tlb),(pte));                   \
@@ -53,7 +53,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_page((unsigned long)pmd);
 }
 
-#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
+#define __pmd_free_tlb(tlb,x, address)   tlb_remove_page((tlb),virt_to_page(x))
 #endif
 
 #define check_pgt_cache()      do { } while (0)
index 62274ab9471fe6f8eb0de14368acf05b65e17691..fd911f855367a2d55506d7b002fce51cd2039ec2 100644 (file)
@@ -32,7 +32,7 @@ struct thread_info {
        .exec_domain =  &default_exec_domain,   \
        .flags =                0,              \
        .cpu =          0,                      \
-       .preempt_count =        1,              \
+       .preempt_count = INIT_PREEMPT_COUNT,    \
        .addr_limit =   KERNEL_DS,              \
        .restart_block =  {                     \
                .fn =  do_no_restart_syscall,   \
index 5240fa1c5e0860debec1fcf56daf1e3db30970ec..660caedac9eb70bb3314beb5b1e87a3d3e876bef 100644 (file)
@@ -116,11 +116,11 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
                __tlb_remove_tlb_entry(tlb, ptep, address);     \
        } while (0)
 
-#define pte_free_tlb(tlb, ptep) __pte_free_tlb(tlb, ptep)
+#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
 
-#define pud_free_tlb(tlb, pudp) __pud_free_tlb(tlb, pudp)
+#define pud_free_tlb(tlb, pudp, addr) __pud_free_tlb(tlb, pudp, addr)
 
-#define pmd_free_tlb(tlb, pmdp) __pmd_free_tlb(tlb, pmdp)
+#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
 
 #define tlb_migrate_finish(mm) do {} while (0)
 
index 2503d4e64c2a79a2aab7618e9c325aadb428e74d..dc5a667ff791388074804ee547b92370c07f59c6 100644 (file)
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         ((v)->counter)
+static inline int atomic_read(const atomic_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic_set - set atomic variable
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic_set(v, i)       (((v)->counter) = (i))
+static inline void atomic_set(atomic_t *v, int i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic_add - add integer to atomic variable
@@ -200,8 +206,15 @@ static inline int atomic_sub_return(int i, atomic_t *v)
        return atomic_add_return(-i, v);
 }
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline int atomic_xchg(atomic_t *v, int new)
+{
+       return xchg(&v->counter, new);
+}
 
 /**
  * atomic_add_unless - add unless the number is already a given value
@@ -250,45 +263,12 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 /* An 64bit atomic type */
 
 typedef struct {
-       unsigned long long counter;
+       u64 __aligned(8) counter;
 } atomic64_t;
 
 #define ATOMIC64_INIT(val)     { (val) }
 
-/**
- * atomic64_read - read atomic64 variable
- * @ptr: pointer of type atomic64_t
- *
- * Atomically reads the value of @v.
- * Doesn't imply a read memory barrier.
- */
-#define __atomic64_read(ptr)           ((ptr)->counter)
-
-static inline unsigned long long
-cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new)
-{
-       asm volatile(
-
-               LOCK_PREFIX "cmpxchg8b (%[ptr])\n"
-
-                    :          "=A" (old)
-
-                    : [ptr]    "D" (ptr),
-                               "A" (old),
-                               "b" (ll_low(new)),
-                               "c" (ll_high(new))
-
-                    : "memory");
-
-       return old;
-}
-
-static inline unsigned long long
-atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val,
-                unsigned long long new_val)
-{
-       return cmpxchg8b(&ptr->counter, old_val, new_val);
-}
+extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val);
 
 /**
  * atomic64_xchg - xchg atomic64 variable
@@ -298,18 +278,7 @@ atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val,
  * Atomically xchgs the value of @ptr to @new_val and returns
  * the old value.
  */
-
-static inline unsigned long long
-atomic64_xchg(atomic64_t *ptr, unsigned long long new_val)
-{
-       unsigned long long old_val;
-
-       do {
-               old_val = atomic_read(ptr);
-       } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
-
-       return old_val;
-}
+extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val);
 
 /**
  * atomic64_set - set atomic64 variable
@@ -318,10 +287,7 @@ atomic64_xchg(atomic64_t *ptr, unsigned long long new_val)
  *
  * Atomically sets the value of @ptr to @new_val.
  */
-static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val)
-{
-       atomic64_xchg(ptr, new_val);
-}
+extern void atomic64_set(atomic64_t *ptr, u64 new_val);
 
 /**
  * atomic64_read - read atomic64 variable
@@ -329,17 +295,30 @@ static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val)
  *
  * Atomically reads the value of @ptr and returns it.
  */
-static inline unsigned long long atomic64_read(atomic64_t *ptr)
+static inline u64 atomic64_read(atomic64_t *ptr)
 {
-       unsigned long long curr_val;
-
-       do {
-               curr_val = __atomic64_read(ptr);
-       } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val);
-
-       return curr_val;
+       u64 res;
+
+       /*
+        * Note, we inline this atomic64_t primitive because
+        * it only clobbers EAX/EDX and leaves the others
+        * untouched. We also (somewhat subtly) rely on the
+        * fact that cmpxchg8b returns the current 64-bit value
+        * of the memory location we are touching:
+        */
+       asm volatile(
+               "mov %%ebx, %%eax\n\t"
+               "mov %%ecx, %%edx\n\t"
+               LOCK_PREFIX "cmpxchg8b %1\n"
+                       : "=&A" (res)
+                       : "m" (*ptr)
+               );
+
+       return res;
 }
 
+extern u64 atomic64_read(atomic64_t *ptr);
+
 /**
  * atomic64_add_return - add and return
  * @delta: integer value to add
@@ -347,34 +326,14 @@ static inline unsigned long long atomic64_read(atomic64_t *ptr)
  *
  * Atomically adds @delta to @ptr and returns @delta + *@ptr
  */
-static inline unsigned long long
-atomic64_add_return(unsigned long long delta, atomic64_t *ptr)
-{
-       unsigned long long old_val, new_val;
-
-       do {
-               old_val = atomic_read(ptr);
-               new_val = old_val + delta;
-
-       } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
-
-       return new_val;
-}
-
-static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr)
-{
-       return atomic64_add_return(-delta, ptr);
-}
+extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr);
 
-static inline long atomic64_inc_return(atomic64_t *ptr)
-{
-       return atomic64_add_return(1, ptr);
-}
-
-static inline long atomic64_dec_return(atomic64_t *ptr)
-{
-       return atomic64_sub_return(1, ptr);
-}
+/*
+ * Other variants with different arithmetic operators:
+ */
+extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr);
+extern u64 atomic64_inc_return(atomic64_t *ptr);
+extern u64 atomic64_dec_return(atomic64_t *ptr);
 
 /**
  * atomic64_add - add integer to atomic64 variable
@@ -383,10 +342,7 @@ static inline long atomic64_dec_return(atomic64_t *ptr)
  *
  * Atomically adds @delta to @ptr.
  */
-static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr)
-{
-       atomic64_add_return(delta, ptr);
-}
+extern void atomic64_add(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_sub - subtract the atomic64 variable
@@ -395,10 +351,7 @@ static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr)
  *
  * Atomically subtracts @delta from @ptr.
  */
-static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr)
-{
-       atomic64_add(-delta, ptr);
-}
+extern void atomic64_sub(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_sub_and_test - subtract value from variable and test result
@@ -409,13 +362,7 @@ static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr)
  * true if the result is zero, or false for all
  * other cases.
  */
-static inline int
-atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr)
-{
-       unsigned long long old_val = atomic64_sub_return(delta, ptr);
-
-       return old_val == 0;
-}
+extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr);
 
 /**
  * atomic64_inc - increment atomic64 variable
@@ -423,10 +370,7 @@ atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr)
  *
  * Atomically increments @ptr by 1.
  */
-static inline void atomic64_inc(atomic64_t *ptr)
-{
-       atomic64_add(1, ptr);
-}
+extern void atomic64_inc(atomic64_t *ptr);
 
 /**
  * atomic64_dec - decrement atomic64 variable
@@ -434,10 +378,7 @@ static inline void atomic64_inc(atomic64_t *ptr)
  *
  * Atomically decrements @ptr by 1.
  */
-static inline void atomic64_dec(atomic64_t *ptr)
-{
-       atomic64_sub(1, ptr);
-}
+extern void atomic64_dec(atomic64_t *ptr);
 
 /**
  * atomic64_dec_and_test - decrement and test
@@ -447,10 +388,7 @@ static inline void atomic64_dec(atomic64_t *ptr)
  * returns true if the result is 0, or false for all other
  * cases.
  */
-static inline int atomic64_dec_and_test(atomic64_t *ptr)
-{
-       return atomic64_sub_and_test(1, ptr);
-}
+extern int atomic64_dec_and_test(atomic64_t *ptr);
 
 /**
  * atomic64_inc_and_test - increment and test
@@ -460,10 +398,7 @@ static inline int atomic64_dec_and_test(atomic64_t *ptr)
  * and returns true if the result is zero, or false for all
  * other cases.
  */
-static inline int atomic64_inc_and_test(atomic64_t *ptr)
-{
-       return atomic64_sub_and_test(-1, ptr);
-}
+extern int atomic64_inc_and_test(atomic64_t *ptr);
 
 /**
  * atomic64_add_negative - add and test if negative
@@ -474,13 +409,7 @@ static inline int atomic64_inc_and_test(atomic64_t *ptr)
  * if the result is negative, or false when
  * result is greater than or equal to zero.
  */
-static inline int
-atomic64_add_negative(unsigned long long delta, atomic64_t *ptr)
-{
-       long long old_val = atomic64_add_return(delta, ptr);
-
-       return old_val < 0;
-}
+extern int atomic64_add_negative(u64 delta, atomic64_t *ptr);
 
 #include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_32_H */
index 0d6360220007b2bc3a35952a7fa4830c837ad4af..d605dc268e798b5bb9e0a5df36de3e5aa88d0e5f 100644 (file)
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         ((v)->counter)
+static inline int atomic_read(const atomic_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic_set - set atomic variable
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic_set(v, i)               (((v)->counter) = (i))
+static inline void atomic_set(atomic_t *v, int i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic_add - add integer to atomic variable
@@ -192,7 +198,10 @@ static inline int atomic_sub_return(int i, atomic_t *v)
  * Atomically reads the value of @v.
  * Doesn't imply a read memory barrier.
  */
-#define atomic64_read(v)               ((v)->counter)
+static inline long atomic64_read(const atomic64_t *v)
+{
+       return v->counter;
+}
 
 /**
  * atomic64_set - set atomic64 variable
@@ -201,7 +210,10 @@ static inline int atomic_sub_return(int i, atomic_t *v)
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic64_set(v, i)             (((v)->counter) = (i))
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+       v->counter = i;
+}
 
 /**
  * atomic64_add - add integer to atomic64 variable
@@ -355,11 +367,25 @@ static inline long atomic64_sub_return(long i, atomic64_t *v)
 #define atomic64_inc_return(v)  (atomic64_add_return(1, (v)))
 #define atomic64_dec_return(v)  (atomic64_sub_return(1, (v)))
 
-#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline long atomic64_xchg(atomic64_t *v, long new)
+{
+       return xchg(&v->counter, new);
+}
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
+static inline long atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
+static inline long atomic_xchg(atomic_t *v, int new)
+{
+       return xchg(&v->counter, new);
+}
 
 /**
  * atomic_add_unless - add unless the number is a given value
index daf866ed0612413f3781cdf6f863e8038daebe85..330ee807f89e7e007a93d093c08b9108b3af22d0 100644 (file)
@@ -161,6 +161,7 @@ extern int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr);
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
+extern void ioapic_insert_resources(void);
 
 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
 extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
@@ -180,6 +181,7 @@ extern void ioapic_write_entry(int apic, int pin,
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
 static inline void ioapic_init_mappings(void)  { }
+static inline void ioapic_insert_resources(void) { }
 
 static inline void probe_nr_irqs_gsi(void)     { }
 #endif
index d31c4a684078080ebe48fbc4d90ebd7f67dce568..33600a66755ff9e8931695c1e5eada1e7bb530ac 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/hw_irq.h>
 #include <asm/kvm_para.h>
 
-/*G:031 But first, how does our Guest contact the Host to ask for privileged
+/*G:030 But first, how does our Guest contact the Host to ask for privileged
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
index dd14c54ac718f465ebccf0b486b421f3d3937c6b..0e8c2a0fd9222d4b75793fb664591de22461e7d7 100644 (file)
@@ -46,7 +46,13 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte)
        __free_page(pte);
 }
 
-extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
+extern void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
+
+static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
+                                 unsigned long address)
+{
+       ___pte_free_tlb(tlb, pte);
+}
 
 static inline void pmd_populate_kernel(struct mm_struct *mm,
                                       pmd_t *pmd, pte_t *pte)
@@ -78,7 +84,13 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_page((unsigned long)pmd);
 }
 
-extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
+extern void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
+
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+                                 unsigned long adddress)
+{
+       ___pmd_free_tlb(tlb, pmd);
+}
 
 #ifdef CONFIG_X86_PAE
 extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
@@ -108,7 +120,14 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
        free_page((unsigned long)pud);
 }
 
-extern void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
+extern void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
+
+static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
+                                 unsigned long address)
+{
+       ___pud_free_tlb(tlb, pud);
+}
+
 #endif /* PAGETABLE_LEVELS > 3 */
 #endif /* PAGETABLE_LEVELS > 2 */
 
index b7e5db8763994cf3164ecf8273f7ec725be9215c..4e77853321dbcca412c52cf35c437bbff2442af8 100644 (file)
@@ -302,4 +302,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
 
+/* The {read|write|spin}_lock() on x86 are full memory barriers. */
+static inline void smp_mb__after_lock(void) { }
+#define ARCH_HAS_SMP_MB_AFTER_LOCK
+
 #endif /* _ASM_X86_SPINLOCK_H */
index f517944b2b176618f51d9791adb9fed4f08864ae..cf86a5e73815dde6fb2e0fa997b8628555584063 100644 (file)
@@ -3,6 +3,8 @@
 
 extern int kstack_depth_to_print;
 
+int x86_is_stack_id(int id, char *name);
+
 /* Generic stack tracer with callbacks */
 
 struct stacktrace_ops {
index b0783520988b8bba544ad79dc38d4ea4580876f6..fad7d40b75f898e8a3651265f573c313a479c4ea 100644 (file)
@@ -49,7 +49,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 20e6a795e16006500dc151b8a98315b94b32fa71..d2c6c930b491916843e76d2c6838e53b5890301b 100644 (file)
@@ -212,9 +212,9 @@ extern int __get_user_bad(void);
                     : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
 #else
 #define __put_user_asm_u64(x, ptr, retval, errret) \
-       __put_user_asm(x, ptr, retval, "q", "", "Zr", errret)
+       __put_user_asm(x, ptr, retval, "q", "", "er", errret)
 #define __put_user_asm_ex_u64(x, addr) \
-       __put_user_asm_ex(x, addr, "q", "", "Zr")
+       __put_user_asm_ex(x, addr, "q", "", "er")
 #define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
 #endif
 
index 8cc687326eb80f20726852c9ba66c68837e8176a..db24b215fc50668bcf3f9da0f6757016aab7956e 100644 (file)
@@ -88,11 +88,11 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
                              ret, "l", "k", "ir", 4);
                return ret;
        case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                             ret, "q", "", "ir", 8);
+                             ret, "q", "", "er", 8);
                return ret;
        case 10:
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                              ret, "q", "", "ir", 10);
+                              ret, "q", "", "er", 10);
                if (unlikely(ret))
                        return ret;
                asm("":::"memory");
@@ -101,12 +101,12 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
                return ret;
        case 16:
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                              ret, "q", "", "ir", 16);
+                              ret, "q", "", "er", 16);
                if (unlikely(ret))
                        return ret;
                asm("":::"memory");
                __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
-                              ret, "q", "", "ir", 8);
+                              ret, "q", "", "er", 8);
                return ret;
        default:
                return copy_user_generic((__force void *)dst, src, size);
@@ -157,7 +157,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
                               ret, "q", "", "=r", 8);
                if (likely(!ret))
                        __put_user_asm(tmp, (u64 __user *)dst,
-                                      ret, "q", "", "ir", 8);
+                                      ret, "q", "", "er", 8);
                return ret;
        }
        default:
index 69328ac8de9c86e106d30af1337a80ab0d4488b1..8952a5890281cc363094cc2f67fed1159e6d7674 100644 (file)
@@ -652,7 +652,8 @@ static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
        return ret && es7000_apic_is_cluster();
 }
 
-struct apic apic_es7000_cluster = {
+/* We've been warned by a false positive warning.Use __refdata to keep calm. */
+struct apic __refdata apic_es7000_cluster = {
 
        .name                           = "es7000",
        .probe                          = probe_es7000,
index 90b5e6efa938ed58ee846ba6969c3c2fc762fb7c..2284a4812b68cfb83ab987388d058004ccb5ee55 100644 (file)
@@ -4181,28 +4181,20 @@ fake_ioapic_page:
        }
 }
 
-static int __init ioapic_insert_resources(void)
+void __init ioapic_insert_resources(void)
 {
        int i;
        struct resource *r = ioapic_resources;
 
        if (!r) {
-               if (nr_ioapics > 0) {
+               if (nr_ioapics > 0)
                        printk(KERN_ERR
                                "IO APIC resources couldn't be allocated.\n");
-                       return -1;
-               }
-               return 0;
+               return;
        }
 
        for (i = 0; i < nr_ioapics; i++) {
                insert_resource(&iomem_resource, r);
                r++;
        }
-
-       return 0;
 }
-
-/* Insert the IO APIC resources after PCI initialization has occured to handle
- * IO APICS that are mapped in on a BAR in PCI space. */
-late_initcall(ioapic_insert_resources);
index 533e59c6fc823a7bb3813cedb74f921765b5d434..ca96e68f0d23230efb4aa74e3227d9d584d4a237 100644 (file)
@@ -493,7 +493,8 @@ static void numaq_setup_portio_remap(void)
                (u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
 }
 
-struct apic apic_numaq = {
+/* Use __refdata to keep false positive warning calm.  */
+struct apic __refdata apic_numaq = {
 
        .name                           = "NUMAQ",
        .probe                          = probe_numaq,
index 28e5f59560429a7bb754a1dca7cb93935d481e07..e2485b03f1cf2649341c9c8d9412495f894eeaa4 100644 (file)
@@ -356,7 +356,7 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
 #endif
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
        /* check CPU config space for extended APIC ID */
-       if (c->x86 >= 0xf) {
+       if (cpu_has_apic && c->x86 >= 0xf) {
                unsigned int val;
                val = read_pci_config(0, 24, 0, 0x68);
                if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18)))
index 484c1e5f658e6b5d932566cd41f7813c44d00b71..1cfb623ce11c9aa7217ea5d1f794029c10ec3607 100644 (file)
@@ -1692,17 +1692,15 @@ static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
                                const char *buf, size_t siz)
 {
        char *p;
-       int len;
 
        strncpy(mce_helper, buf, sizeof(mce_helper));
        mce_helper[sizeof(mce_helper)-1] = 0;
-       len = strlen(mce_helper);
        p = strchr(mce_helper, '\n');
 
-       if (*p)
+       if (p)
                *p = 0;
 
-       return len;
+       return strlen(mce_helper) + !!p;
 }
 
 static ssize_t set_ignore_ce(struct sys_device *s,
index d4cf4ce19aac5f5965a94f115fef1acae7510ab9..a7aa8f900954811e046f397547a19e88291aaeb3 100644 (file)
@@ -65,6 +65,52 @@ static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = {
        .enabled = 1,
 };
 
+/*
+ * Not sure about some of these
+ */
+static const u64 p6_perfmon_event_map[] =
+{
+  [PERF_COUNT_HW_CPU_CYCLES]           = 0x0079,
+  [PERF_COUNT_HW_INSTRUCTIONS]         = 0x00c0,
+  [PERF_COUNT_HW_CACHE_REFERENCES]     = 0x0000,
+  [PERF_COUNT_HW_CACHE_MISSES]         = 0x0000,
+  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]  = 0x00c4,
+  [PERF_COUNT_HW_BRANCH_MISSES]                = 0x00c5,
+  [PERF_COUNT_HW_BUS_CYCLES]           = 0x0062,
+};
+
+static u64 p6_pmu_event_map(int event)
+{
+       return p6_perfmon_event_map[event];
+}
+
+/*
+ * Counter setting that is specified not to count anything.
+ * We use this to effectively disable a counter.
+ *
+ * L2_RQSTS with 0 MESI unit mask.
+ */
+#define P6_NOP_COUNTER                 0x0000002EULL
+
+static u64 p6_pmu_raw_event(u64 event)
+{
+#define P6_EVNTSEL_EVENT_MASK          0x000000FFULL
+#define P6_EVNTSEL_UNIT_MASK           0x0000FF00ULL
+#define P6_EVNTSEL_EDGE_MASK           0x00040000ULL
+#define P6_EVNTSEL_INV_MASK            0x00800000ULL
+#define P6_EVNTSEL_COUNTER_MASK                0xFF000000ULL
+
+#define P6_EVNTSEL_MASK                        \
+       (P6_EVNTSEL_EVENT_MASK |        \
+        P6_EVNTSEL_UNIT_MASK  |        \
+        P6_EVNTSEL_EDGE_MASK  |        \
+        P6_EVNTSEL_INV_MASK   |        \
+        P6_EVNTSEL_COUNTER_MASK)
+
+       return event & P6_EVNTSEL_MASK;
+}
+
+
 /*
  * Intel PerfMon v3. Used on Core2 and later.
  */
@@ -666,6 +712,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
 {
        struct perf_counter_attr *attr = &counter->attr;
        struct hw_perf_counter *hwc = &counter->hw;
+       u64 config;
        int err;
 
        if (!x86_pmu_initialized())
@@ -718,14 +765,40 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
 
        if (attr->config >= x86_pmu.max_events)
                return -EINVAL;
+
        /*
         * The generic map:
         */
-       hwc->config |= x86_pmu.event_map(attr->config);
+       config = x86_pmu.event_map(attr->config);
+
+       if (config == 0)
+               return -ENOENT;
+
+       if (config == -1LL)
+               return -EINVAL;
+
+       hwc->config |= config;
 
        return 0;
 }
 
+static void p6_pmu_disable_all(void)
+{
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+       u64 val;
+
+       if (!cpuc->enabled)
+               return;
+
+       cpuc->enabled = 0;
+       barrier();
+
+       /* p6 only has one enable register */
+       rdmsrl(MSR_P6_EVNTSEL0, val);
+       val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
+       wrmsrl(MSR_P6_EVNTSEL0, val);
+}
+
 static void intel_pmu_disable_all(void)
 {
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
@@ -767,6 +840,23 @@ void hw_perf_disable(void)
        return x86_pmu.disable_all();
 }
 
+static void p6_pmu_enable_all(void)
+{
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+       unsigned long val;
+
+       if (cpuc->enabled)
+               return;
+
+       cpuc->enabled = 1;
+       barrier();
+
+       /* p6 only has one enable register */
+       rdmsrl(MSR_P6_EVNTSEL0, val);
+       val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+       wrmsrl(MSR_P6_EVNTSEL0, val);
+}
+
 static void intel_pmu_enable_all(void)
 {
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
@@ -784,13 +874,13 @@ static void amd_pmu_enable_all(void)
        barrier();
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+               struct perf_counter *counter = cpuc->counters[idx];
                u64 val;
 
                if (!test_bit(idx, cpuc->active_mask))
                        continue;
-               rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
-               if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
-                       continue;
+
+               val = counter->hw.config;
                val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
                wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
        }
@@ -819,16 +909,13 @@ static inline void intel_pmu_ack_status(u64 ack)
 
 static inline void x86_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
 {
-       int err;
-       err = checking_wrmsrl(hwc->config_base + idx,
+       (void)checking_wrmsrl(hwc->config_base + idx,
                              hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE);
 }
 
 static inline void x86_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
 {
-       int err;
-       err = checking_wrmsrl(hwc->config_base + idx,
-                             hwc->config);
+       (void)checking_wrmsrl(hwc->config_base + idx, hwc->config);
 }
 
 static inline void
@@ -836,13 +923,24 @@ intel_pmu_disable_fixed(struct hw_perf_counter *hwc, int __idx)
 {
        int idx = __idx - X86_PMC_IDX_FIXED;
        u64 ctrl_val, mask;
-       int err;
 
        mask = 0xfULL << (idx * 4);
 
        rdmsrl(hwc->config_base, ctrl_val);
        ctrl_val &= ~mask;
-       err = checking_wrmsrl(hwc->config_base, ctrl_val);
+       (void)checking_wrmsrl(hwc->config_base, ctrl_val);
+}
+
+static inline void
+p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
+{
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+       u64 val = P6_NOP_COUNTER;
+
+       if (cpuc->enabled)
+               val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+
+       (void)checking_wrmsrl(hwc->config_base + idx, val);
 }
 
 static inline void
@@ -943,6 +1041,19 @@ intel_pmu_enable_fixed(struct hw_perf_counter *hwc, int __idx)
        err = checking_wrmsrl(hwc->config_base, ctrl_val);
 }
 
+static void p6_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
+{
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+       u64 val;
+
+       val = hwc->config;
+       if (cpuc->enabled)
+               val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+
+       (void)checking_wrmsrl(hwc->config_base + idx, val);
+}
+
+
 static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
 {
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
@@ -959,8 +1070,6 @@ static void amd_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
 
        if (cpuc->enabled)
                x86_pmu_enable_counter(hwc, idx);
-       else
-               x86_pmu_disable_counter(hwc, idx);
 }
 
 static int
@@ -1176,6 +1285,49 @@ static void intel_pmu_reset(void)
        local_irq_restore(flags);
 }
 
+static int p6_pmu_handle_irq(struct pt_regs *regs)
+{
+       struct perf_sample_data data;
+       struct cpu_hw_counters *cpuc;
+       struct perf_counter *counter;
+       struct hw_perf_counter *hwc;
+       int idx, handled = 0;
+       u64 val;
+
+       data.regs = regs;
+       data.addr = 0;
+
+       cpuc = &__get_cpu_var(cpu_hw_counters);
+
+       for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+               if (!test_bit(idx, cpuc->active_mask))
+                       continue;
+
+               counter = cpuc->counters[idx];
+               hwc = &counter->hw;
+
+               val = x86_perf_counter_update(counter, hwc, idx);
+               if (val & (1ULL << (x86_pmu.counter_bits - 1)))
+                       continue;
+
+               /*
+                * counter overflow
+                */
+               handled         = 1;
+               data.period     = counter->hw.last_period;
+
+               if (!x86_perf_counter_set_period(counter, hwc, idx))
+                       continue;
+
+               if (perf_counter_overflow(counter, 1, &data))
+                       p6_pmu_disable_counter(hwc, idx);
+       }
+
+       if (handled)
+               inc_irq_stat(apic_perf_irqs);
+
+       return handled;
+}
 
 /*
  * This handler is triggered by the local APIC, so the APIC IRQ handling
@@ -1185,14 +1337,13 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
 {
        struct perf_sample_data data;
        struct cpu_hw_counters *cpuc;
-       int bit, cpu, loops;
+       int bit, loops;
        u64 ack, status;
 
        data.regs = regs;
        data.addr = 0;
 
-       cpu = smp_processor_id();
-       cpuc = &per_cpu(cpu_hw_counters, cpu);
+       cpuc = &__get_cpu_var(cpu_hw_counters);
 
        perf_disable();
        status = intel_pmu_get_status();
@@ -1249,14 +1400,13 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
        struct cpu_hw_counters *cpuc;
        struct perf_counter *counter;
        struct hw_perf_counter *hwc;
-       int cpu, idx, handled = 0;
+       int idx, handled = 0;
        u64 val;
 
        data.regs = regs;
        data.addr = 0;
 
-       cpu = smp_processor_id();
-       cpuc = &per_cpu(cpu_hw_counters, cpu);
+       cpuc = &__get_cpu_var(cpu_hw_counters);
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
                if (!test_bit(idx, cpuc->active_mask))
@@ -1353,6 +1503,32 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
        .priority               = 1
 };
 
+static struct x86_pmu p6_pmu = {
+       .name                   = "p6",
+       .handle_irq             = p6_pmu_handle_irq,
+       .disable_all            = p6_pmu_disable_all,
+       .enable_all             = p6_pmu_enable_all,
+       .enable                 = p6_pmu_enable_counter,
+       .disable                = p6_pmu_disable_counter,
+       .eventsel               = MSR_P6_EVNTSEL0,
+       .perfctr                = MSR_P6_PERFCTR0,
+       .event_map              = p6_pmu_event_map,
+       .raw_event              = p6_pmu_raw_event,
+       .max_events             = ARRAY_SIZE(p6_perfmon_event_map),
+       .max_period             = (1ULL << 31) - 1,
+       .version                = 0,
+       .num_counters           = 2,
+       /*
+        * Counters have 40 bits implemented. However they are designed such
+        * that bits [32-39] are sign extensions of bit 31. As such the
+        * effective width of a counter for P6-like PMU is 32 bits only.
+        *
+        * See IA-32 Intel Architecture Software developer manual Vol 3B
+        */
+       .counter_bits           = 32,
+       .counter_mask           = (1ULL << 32) - 1,
+};
+
 static struct x86_pmu intel_pmu = {
        .name                   = "Intel",
        .handle_irq             = intel_pmu_handle_irq,
@@ -1392,6 +1568,37 @@ static struct x86_pmu amd_pmu = {
        .max_period             = (1ULL << 47) - 1,
 };
 
+static int p6_pmu_init(void)
+{
+       switch (boot_cpu_data.x86_model) {
+       case 1:
+       case 3:  /* Pentium Pro */
+       case 5:
+       case 6:  /* Pentium II */
+       case 7:
+       case 8:
+       case 11: /* Pentium III */
+               break;
+       case 9:
+       case 13:
+               /* Pentium M */
+               break;
+       default:
+               pr_cont("unsupported p6 CPU model %d ",
+                       boot_cpu_data.x86_model);
+               return -ENODEV;
+       }
+
+       if (!cpu_has_apic) {
+               pr_info("no Local APIC, try rebooting with lapic");
+               return -ENODEV;
+       }
+
+       x86_pmu                         = p6_pmu;
+
+       return 0;
+}
+
 static int intel_pmu_init(void)
 {
        union cpuid10_edx edx;
@@ -1400,8 +1607,14 @@ static int intel_pmu_init(void)
        unsigned int ebx;
        int version;
 
-       if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
+       if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+               /* check for P6 processor family */
+          if (boot_cpu_data.x86 == 6) {
+               return p6_pmu_init();
+          } else {
                return -ENODEV;
+          }
+       }
 
        /*
         * Check whether the Architectural PerfMon supports
@@ -1561,6 +1774,7 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip)
 
 static DEFINE_PER_CPU(struct perf_callchain_entry, irq_entry);
 static DEFINE_PER_CPU(struct perf_callchain_entry, nmi_entry);
+static DEFINE_PER_CPU(int, in_nmi_frame);
 
 
 static void
@@ -1576,7 +1790,9 @@ static void backtrace_warning(void *data, char *msg)
 
 static int backtrace_stack(void *data, char *name)
 {
-       /* Process all stacks: */
+       per_cpu(in_nmi_frame, smp_processor_id()) =
+                       x86_is_stack_id(NMI_STACK, name);
+
        return 0;
 }
 
@@ -1584,6 +1800,9 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
 {
        struct perf_callchain_entry *entry = data;
 
+       if (per_cpu(in_nmi_frame, smp_processor_id()))
+               return;
+
        if (reliable)
                callchain_store(entry, addr);
 }
index d593cd1f58dcca22925f10e2b3669435a4a25557..bca5fba91c9ea3d62eed95643cacdb90e2a32770 100644 (file)
 
 #include "dumpstack.h"
 
+/* Just a stub for now */
+int x86_is_stack_id(int id, char *name)
+{
+       return 0;
+}
+
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
index d35db5993fd68e3a740ee36ade60edf78d14fae8..54b0a3276766c3ac5180d7d6c11469a2c5f00979 100644 (file)
 
 #include "dumpstack.h"
 
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
-{
-       static char ids[][8] = {
+
+static char x86_stack_ids[][8] = {
                [DEBUG_STACK - 1] = "#DB",
                [NMI_STACK - 1] = "NMI",
                [DOUBLEFAULT_STACK - 1] = "#DF",
@@ -33,6 +31,15 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
 #endif
        };
+
+int x86_is_stack_id(int id, char *name)
+{
+       return x86_stack_ids[id - 1] == name;
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+                                       unsigned *usedp, char **idp)
+{
        unsigned k;
 
        /*
@@ -61,7 +68,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        if (*usedp & (1U << k))
                                break;
                        *usedp |= 1U << k;
-                       *idp = ids[k];
+                       *idp = x86_stack_ids[k];
                        return (unsigned long *)end;
                }
                /*
@@ -81,12 +88,13 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        do {
                                ++j;
                                end -= EXCEPTION_STKSZ;
-                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+                               x86_stack_ids[j][4] = '1' +
+                                               (j - N_EXCEPTION_STACKS);
                        } while (stack < end - EXCEPTION_STKSZ);
                        if (*usedp & (1U << j))
                                break;
                        *usedp |= 1U << j;
-                       *idp = ids[j];
+                       *idp = x86_stack_ids[j];
                        return (unsigned long *)end;
                }
 #endif
index 696f0e475c2d6d8b8b5f2eb4a22e4d934a00e561..92b7703d3d58e6ad278e45d733fdcac1505772fa 100644 (file)
@@ -187,7 +187,7 @@ static void __init apic_intr_init(void)
 #ifdef CONFIG_X86_THERMAL_VECTOR
        alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
 #endif
-#ifdef CONFIG_X86_THRESHOLD
+#ifdef CONFIG_X86_MCE_THRESHOLD
        alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 #endif
 #if defined(CONFIG_X86_NEW_MCE) && defined(CONFIG_X86_LOCAL_APIC)
index 846510b78a092324bfa7adc61ee72ee25e8792cc..2a62d843f015a4804440dce2e502bb3aea47abc7 100644 (file)
@@ -347,7 +347,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
 
 static struct irqaction mfgptirq  = {
        .handler = mfgpt_tick,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
        .name = "mfgpt-timer"
 };
 
index 4f9c55f3a7c0f7e2590a5e248428bd19aa0d5c37..03801f2f761fc312ba80353425c1cc7243a0105f 100644 (file)
@@ -60,7 +60,7 @@ static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
                "adc  %5,%%edx ; "
                : "=A" (product), "=r" (tmp1), "=r" (tmp2)
                : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
-#elif __x86_64__
+#elif defined(__x86_64__)
        __asm__ (
                "mul %%rdx ; shrd $32,%%rdx,%%rax"
                : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
index d2d1ce8170f06c8573ac022f4e49dfc59a371c9b..508e982dd072404d14005a90a8c007682e10fb89 100644 (file)
@@ -249,6 +249,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
                },
        },
+       {       /* Handle problems with rebooting on CompuLab SBC-FITPC2 */
+               .callback = set_bios_reboot,
+               .ident = "CompuLab SBC-FITPC2",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
+               },
+       },
        { }
 };
 
index de2cab13284495da052984e093508f5884af3de1..63f32d220ef22e2d681078ec556698e15ff7645f 100644 (file)
@@ -672,6 +672,19 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
                },
        },
+       {
+       /*
+        * AMI BIOS with low memory corruption was found on Intel DG45ID board.
+        * It hase different DMI_BIOS_VENDOR = "Intel Corp.", for now we will
+        * match only DMI_BOARD_NAME and see if there is more bad products
+        * with this vendor.
+        */
+               .callback = dmi_low_memory_corruption,
+               .ident = "AMI BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "DG45ID"),
+               },
+       },
 #endif
        {}
 };
index 367e878820418789055a6a2da48aa27350ada443..59f31d2dd43567f6c995ccf322f666148cc7fb39 100644 (file)
@@ -112,11 +112,6 @@ SECTIONS
                _sdata = .;
                DATA_DATA
                CONSTRUCTORS
-
-#ifdef CONFIG_X86_64
-               /* End of data section */
-               _edata = .;
-#endif
        } :data
 
 #ifdef CONFIG_X86_32
@@ -156,10 +151,8 @@ SECTIONS
        .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
                *(.data.read_mostly)
 
-#ifdef CONFIG_X86_32
                /* End of data section */
                _edata = .;
-#endif
        }
 
 #ifdef CONFIG_X86_64
index 7bc65f0f62c4fc51607dd443641d1273cb4ebb03..f2bf1f73d468942590d5c914e874d24fa23d22b0 100644 (file)
@@ -379,6 +379,11 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
 
        native_cpuid(ax, bx, cx, dx);
        switch (function) {
+       case 0: /* ID and highest CPUID.  Futureproof a little by sticking to
+                * older ones. */
+               if (*ax > 5)
+                       *ax = 5;
+               break;
        case 1: /* Basic feature request. */
                /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
                *cx &= 0x00002201;
@@ -1079,7 +1084,7 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
        return insn_len;
 }
 
-/*G:030 Once we get to lguest_init(), we know we're a Guest.  The various
+/*G:029 Once we get to lguest_init(), we know we're a Guest.  The various
  * pv_ops structures in the kernel provide points for (almost) every routine we
  * have to override to avoid privileged instructions. */
 __init void lguest_init(void)
index f9d35632666b06bb0b9bf072176777dbd94c39cc..07c31899c9c24b8f59d0d9c8bacf9c3dd56444da 100644 (file)
@@ -10,6 +10,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 
 ifeq ($(CONFIG_X86_32),y)
+        obj-y += atomic64_32.o
         lib-y += checksum_32.o
         lib-y += strstr_32.o
         lib-y += semaphore_32.o string_32.o
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c
new file mode 100644 (file)
index 0000000..824fa0b
--- /dev/null
@@ -0,0 +1,230 @@
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/cmpxchg.h>
+#include <asm/atomic.h>
+
+static noinline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new)
+{
+       u32 low = new;
+       u32 high = new >> 32;
+
+       asm volatile(
+               LOCK_PREFIX "cmpxchg8b %1\n"
+                    : "+A" (old), "+m" (*ptr)
+                    :  "b" (low),  "c" (high)
+                    );
+       return old;
+}
+
+u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val)
+{
+       return cmpxchg8b(&ptr->counter, old_val, new_val);
+}
+EXPORT_SYMBOL(atomic64_cmpxchg);
+
+/**
+ * atomic64_xchg - xchg atomic64 variable
+ * @ptr:      pointer to type atomic64_t
+ * @new_val:  value to assign
+ *
+ * Atomically xchgs the value of @ptr to @new_val and returns
+ * the old value.
+ */
+u64 atomic64_xchg(atomic64_t *ptr, u64 new_val)
+{
+       /*
+        * Try first with a (possibly incorrect) assumption about
+        * what we have there. We'll do two loops most likely,
+        * but we'll get an ownership MESI transaction straight away
+        * instead of a read transaction followed by a
+        * flush-for-ownership transaction:
+        */
+       u64 old_val, real_val = 0;
+
+       do {
+               old_val = real_val;
+
+               real_val = atomic64_cmpxchg(ptr, old_val, new_val);
+
+       } while (real_val != old_val);
+
+       return old_val;
+}
+EXPORT_SYMBOL(atomic64_xchg);
+
+/**
+ * atomic64_set - set atomic64 variable
+ * @ptr:      pointer to type atomic64_t
+ * @new_val:  value to assign
+ *
+ * Atomically sets the value of @ptr to @new_val.
+ */
+void atomic64_set(atomic64_t *ptr, u64 new_val)
+{
+       atomic64_xchg(ptr, new_val);
+}
+EXPORT_SYMBOL(atomic64_set);
+
+/**
+EXPORT_SYMBOL(atomic64_read);
+ * atomic64_add_return - add and return
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr and returns @delta + *@ptr
+ */
+noinline u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
+{
+       /*
+        * Try first with a (possibly incorrect) assumption about
+        * what we have there. We'll do two loops most likely,
+        * but we'll get an ownership MESI transaction straight away
+        * instead of a read transaction followed by a
+        * flush-for-ownership transaction:
+        */
+       u64 old_val, new_val, real_val = 0;
+
+       do {
+               old_val = real_val;
+               new_val = old_val + delta;
+
+               real_val = atomic64_cmpxchg(ptr, old_val, new_val);
+
+       } while (real_val != old_val);
+
+       return new_val;
+}
+EXPORT_SYMBOL(atomic64_add_return);
+
+u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
+{
+       return atomic64_add_return(-delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_sub_return);
+
+u64 atomic64_inc_return(atomic64_t *ptr)
+{
+       return atomic64_add_return(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc_return);
+
+u64 atomic64_dec_return(atomic64_t *ptr)
+{
+       return atomic64_sub_return(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec_return);
+
+/**
+ * atomic64_add - add integer to atomic64 variable
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr.
+ */
+void atomic64_add(u64 delta, atomic64_t *ptr)
+{
+       atomic64_add_return(delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_add);
+
+/**
+ * atomic64_sub - subtract the atomic64 variable
+ * @delta: integer value to subtract
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically subtracts @delta from @ptr.
+ */
+void atomic64_sub(u64 delta, atomic64_t *ptr)
+{
+       atomic64_add(-delta, ptr);
+}
+EXPORT_SYMBOL(atomic64_sub);
+
+/**
+ * atomic64_sub_and_test - subtract value from variable and test result
+ * @delta: integer value to subtract
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically subtracts @delta from @ptr and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
+{
+       u64 new_val = atomic64_sub_return(delta, ptr);
+
+       return new_val == 0;
+}
+EXPORT_SYMBOL(atomic64_sub_and_test);
+
+/**
+ * atomic64_inc - increment atomic64 variable
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically increments @ptr by 1.
+ */
+void atomic64_inc(atomic64_t *ptr)
+{
+       atomic64_add(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc);
+
+/**
+ * atomic64_dec - decrement atomic64 variable
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically decrements @ptr by 1.
+ */
+void atomic64_dec(atomic64_t *ptr)
+{
+       atomic64_sub(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec);
+
+/**
+ * atomic64_dec_and_test - decrement and test
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically decrements @ptr by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+int atomic64_dec_and_test(atomic64_t *ptr)
+{
+       return atomic64_sub_and_test(1, ptr);
+}
+EXPORT_SYMBOL(atomic64_dec_and_test);
+
+/**
+ * atomic64_inc_and_test - increment and test
+ * @ptr: pointer to type atomic64_t
+ *
+ * Atomically increments @ptr by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+int atomic64_inc_and_test(atomic64_t *ptr)
+{
+       return atomic64_sub_and_test(-1, ptr);
+}
+EXPORT_SYMBOL(atomic64_inc_and_test);
+
+/**
+ * atomic64_add_negative - add and test if negative
+ * @delta: integer value to add
+ * @ptr:   pointer to type atomic64_t
+ *
+ * Atomically adds @delta to @ptr and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+int atomic64_add_negative(u64 delta, atomic64_t *ptr)
+{
+       s64 new_val = atomic64_add_return(delta, ptr);
+
+       return new_val < 0;
+}
+EXPORT_SYMBOL(atomic64_add_negative);
index 7c8ca91bb9ecbacbccc42df711222e7abdc32310..1f118d462acc242990eb7a796b6832d8d90bc442 100644 (file)
@@ -751,7 +751,7 @@ survive:
 
                        if (retval == -ENOMEM && is_global_init(current)) {
                                up_read(&current->mm->mmap_sem);
-                               congestion_wait(WRITE, HZ/50);
+                               congestion_wait(BLK_RW_ASYNC, HZ/50);
                                goto survive;
                        }
 
index 85307cc6e45f951b80a7d49d19cc873b779bd595..bfae139182ffbf0d2c5098d824f9d9ed7d8b6827 100644 (file)
@@ -697,7 +697,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
        if (!printk_ratelimit())
                return;
 
-       printk(KERN_CONT "%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
+       printk("%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
                task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
                tsk->comm, task_pid_nr(tsk), address,
                (void *)regs->ip, (void *)regs->sp, error_code);
index 8e43bdd45456017cd431c2cf9b4678c5b7e9f65d..af8f9650058cfcf59ab46476ac174ec86e41de49 100644 (file)
@@ -25,7 +25,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
        return pte;
 }
 
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
+void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
 {
        pgtable_page_dtor(pte);
        paravirt_release_pte(page_to_pfn(pte));
@@ -33,14 +33,14 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
 }
 
 #if PAGETABLE_LEVELS > 2
-void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
 {
        paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT);
        tlb_remove_page(tlb, virt_to_page(pmd));
 }
 
 #if PAGETABLE_LEVELS > 3
-void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
 {
        paravirt_release_pud(__pa(pud) >> PAGE_SHIFT);
        tlb_remove_page(tlb, virt_to_page(pud));
index 2dfcbf9df2ae8410228e25fb4f559cd75ed1982e..dbb5381f7b3b58ec41f026cd65d592bc1c2871ff 100644 (file)
@@ -79,8 +79,10 @@ static __init void bad_srat(void)
        acpi_numa = -1;
        for (i = 0; i < MAX_LOCAL_APIC; i++)
                apicid_to_node[i] = NUMA_NO_NODE;
-       for (i = 0; i < MAX_NUMNODES; i++)
-               nodes_add[i].start = nodes[i].end = 0;
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               nodes[i].start = nodes[i].end = 0;
+               nodes_add[i].start = nodes_add[i].end = 0;
+       }
        remove_all_active_ranges();
 }
 
index b07dd8d0b321d9e04fd94b307c0f51befdc20933..89b9a5cd63da1d52900a47dd0b269476dd09fb2c 100644 (file)
@@ -390,7 +390,7 @@ static int __init p4_init(char **cpu_type)
 static int force_arch_perfmon;
 static int force_cpu_type(const char *str, struct kernel_param *kp)
 {
-       if (!strcmp(str, "archperfmon")) {
+       if (!strcmp(str, "arch_perfmon")) {
                force_arch_perfmon = 1;
                printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
        }
index 0fb56db16d1813897b7f7fea6df2af75a20fd2a0..52e62e57fedd53a385147cf1399cd84f89f7bc4b 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/pat.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
+#include <asm/io_apic.h>
 
 
 static int
@@ -227,6 +228,12 @@ void __init pcibios_resource_survey(void)
        pcibios_allocate_resources(1);
 
        e820_reserve_resources_late();
+       /*
+        * Insert the IO APIC resources after PCI initialization has
+        * occured to handle IO APICS that are mapped in on a BAR in
+        * PCI space, but before trying to assign unassigned pci res.
+        */
+       ioapic_insert_resources();
 }
 
 /**
index 0f4fe1faf9ba46fed7f9c689f2bb2652fe25923b..13165641cc5153bb9990a634042262f2c120085a 100644 (file)
@@ -80,8 +80,6 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 
 #ifndef __ASSEMBLY__
@@ -92,7 +90,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .addr_limit     = KERNEL_DS,            \
        .restart_block = {                      \
                .fn = do_no_restart_syscall,    \
index 31c220faca02ac9cbb3695f735e0221bdc32104a..0d766f9c1083a59cd4a073cb5da0dfc640a06415 100644 (file)
@@ -42,6 +42,6 @@
 
 #include <asm-generic/tlb.h>
 
-#define __pte_free_tlb(tlb, pte)               pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, address)      pte_free((tlb)->mm, pte)
 
 #endif /* _XTENSA_TLB_H */
index b1cd04087d6a4db5f8ba3e2d9b4f8db1221ed424..418d63619680e8df2b9ab2ba0cdd5f31bcfb4ee4 100644 (file)
@@ -16,9 +16,9 @@ struct queue_sysfs_entry {
 };
 
 static ssize_t
-queue_var_show(unsigned int var, char *page)
+queue_var_show(unsigned long var, char *page)
 {
-       return sprintf(page, "%d\n", var);
+       return sprintf(page, "%lu\n", var);
 }
 
 static ssize_t
@@ -77,7 +77,8 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
 
 static ssize_t queue_ra_show(struct request_queue *q, char *page)
 {
-       int ra_kb = q->backing_dev_info.ra_pages << (PAGE_CACHE_SHIFT - 10);
+       unsigned long ra_kb = q->backing_dev_info.ra_pages <<
+                                       (PAGE_CACHE_SHIFT - 10);
 
        return queue_var_show(ra_kb, (page));
 }
@@ -189,9 +190,9 @@ static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
 
 static ssize_t queue_rq_affinity_show(struct request_queue *q, char *page)
 {
-       unsigned int set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags);
+       bool set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags);
 
-       return queue_var_show(set != 0, page);
+       return queue_var_show(set, page);
 }
 
 static ssize_t
index 87276eb83f7f54576fe8fc65c84605133b3e7000..fd7080ed793599127647baafbed009d8e11ef1af 100644 (file)
@@ -2311,7 +2311,7 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
                goto queue_fail;
 
        cfqq = cic_to_cfqq(cic, is_sync);
-       if (!cfqq) {
+       if (!cfqq || cfqq == &cfqd->oom_cfqq) {
                cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
                cic_set_cfqq(cic, cfqq, is_sync);
        }
index 6f2375339a996a794c17c96d0f32aa724fd1fae2..2d511f9105e16abcf93cad6ac849ad9996661a32 100644 (file)
@@ -101,11 +101,16 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
                return 0;
 
        /*
-        * Don't merge if failfast settings don't match
+        * Don't merge if failfast settings don't match.
+        *
+        * FIXME: The negation in front of each condition is necessary
+        * because bio and request flags use different bit positions
+        * and the accessors return those bits directly.  This
+        * ugliness will soon go away.
         */
-       if (bio_failfast_dev(bio)       != blk_failfast_dev(rq)         ||
-           bio_failfast_transport(bio) != blk_failfast_transport(rq)   ||
-           bio_failfast_driver(bio)    != blk_failfast_driver(rq))
+       if (!bio_failfast_dev(bio)       != !blk_failfast_dev(rq)       ||
+           !bio_failfast_transport(bio) != !blk_failfast_transport(rq) ||
+           !bio_failfast_driver(bio)    != !blk_failfast_driver(rq))
                return 0;
 
        if (!elv_iosched_allow_merge(rq, bio))
index f0e0ce0a607dcc54ce08e17da4b54212d98d20a6..e5b10017a50b121a9288d6d0354bfe9ebb15e499 100644 (file)
@@ -680,3 +680,4 @@ int __init blk_scsi_ioctl_init(void)
        blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
        return 0;
 }
+fs_initcall(blk_scsi_ioctl_init);
index 15a23031833f46e921957c48578723caf9b2446e..958c1fa41900f36ff7a8de1bf51b6d01f7c5720e 100644 (file)
@@ -513,11 +513,16 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+       { PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
        { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
+       { PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
+       { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
        { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
 
        /* 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,
index d0a14cf2bd741240296122e5da4b83a81b496c08..56b8a3ff12865041af813ca0bcfa49db143e5169 100644 (file)
@@ -596,9 +596,12 @@ static const struct ich_laptop ich_laptop[] = {
        { 0x27DF, 0x0005, 0x0280 },     /* ICH7 on Acer 5602WLMi */
        { 0x27DF, 0x1025, 0x0102 },     /* ICH7 on Acer 5602aWLMi */
        { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
+       { 0x27DF, 0x1028, 0x02b0 },     /* ICH7 on unknown Dell */
        { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
        { 0x27DF, 0x103C, 0x30A1 },     /* ICH7 on HP Compaq nc2400 */
+       { 0x27DF, 0x103C, 0x361a },     /* ICH7 on unkown HP  */
        { 0x27DF, 0x1071, 0xD221 },     /* ICH7 on Hercules EC-900 */
+       { 0x27DF, 0x152D, 0x0778 },     /* ICH7 on unknown Intel */
        { 0x24CA, 0x1025, 0x0061 },     /* ICH4 on ACER Aspire 2023WLMi */
        { 0x24CA, 0x1025, 0x003d },     /* ICH4 on ACER TM290 */
        { 0x266F, 0x1025, 0x0066 },     /* ICH6 on ACER Aspire 1694WLMi */
index 045a486a09eae25a16174a7c697e52796dcbc503..8ac98ff16d7deb65f083851013c090a1cb9cfa60 100644 (file)
@@ -1515,6 +1515,7 @@ static int ata_hpa_resize(struct ata_device *dev)
 
                return rc;
        }
+       dev->n_native_sectors = native_sectors;
 
        /* nothing to do? */
        if (native_sectors <= sectors || !ata_ignore_hpa) {
@@ -3392,17 +3393,27 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 
 static int ata_dev_set_mode(struct ata_device *dev)
 {
+       struct ata_port *ap = dev->link->ap;
        struct ata_eh_context *ehc = &dev->link->eh_context;
+       const bool nosetxfer = dev->horkage & ATA_HORKAGE_NOSETXFER;
        const char *dev_err_whine = "";
        int ign_dev_err = 0;
-       unsigned int err_mask;
+       unsigned int err_mask = 0;
        int rc;
 
        dev->flags &= ~ATA_DFLAG_PIO;
        if (dev->xfer_shift == ATA_SHIFT_PIO)
                dev->flags |= ATA_DFLAG_PIO;
 
-       err_mask = ata_dev_set_xfermode(dev);
+       if (nosetxfer && ap->flags & ATA_FLAG_SATA && ata_id_is_sata(dev->id))
+               dev_err_whine = " (SET_XFERMODE skipped)";
+       else {
+               if (nosetxfer)
+                       ata_dev_printk(dev, KERN_WARNING,
+                                      "NOSETXFER but PATA detected - can't "
+                                      "skip SETXFER, might malfunction\n");
+               err_mask = ata_dev_set_xfermode(dev);
+       }
 
        if (err_mask & ~AC_ERR_DEV)
                goto fail;
@@ -4089,6 +4100,7 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
                       unsigned int readid_flags)
 {
        u64 n_sectors = dev->n_sectors;
+       u64 n_native_sectors = dev->n_native_sectors;
        int rc;
 
        if (!ata_dev_enabled(dev))
@@ -4118,16 +4130,30 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
        /* verify n_sectors hasn't changed */
        if (dev->class == ATA_DEV_ATA && n_sectors &&
            dev->n_sectors != n_sectors) {
-               ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+               ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch "
                               "%llu != %llu\n",
                               (unsigned long long)n_sectors,
                               (unsigned long long)dev->n_sectors);
-
-               /* restore original n_sectors */
-               dev->n_sectors = n_sectors;
-
-               rc = -ENODEV;
-               goto fail;
+               /*
+                * Something could have caused HPA to be unlocked
+                * involuntarily.  If n_native_sectors hasn't changed
+                * and the new size matches it, keep the device.
+                */
+               if (dev->n_native_sectors == n_native_sectors &&
+                   dev->n_sectors > n_sectors &&
+                   dev->n_sectors == n_native_sectors) {
+                       ata_dev_printk(dev, KERN_WARNING,
+                                      "new n_sectors matches native, probably "
+                                      "late HPA unlock, continuing\n");
+                       /* keep using the old n_sectors */
+                       dev->n_sectors = n_sectors;
+               } else {
+                       /* restore original n_[native]_sectors and fail */
+                       dev->n_native_sectors = n_native_sectors;
+                       dev->n_sectors = n_sectors;
+                       rc = -ENODEV;
+                       goto fail;
+               }
        }
 
        return 0;
@@ -4297,6 +4323,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* Devices which aren't very happy with higher link speeds */
        { "WD My Book",                 NULL,   ATA_HORKAGE_1_5_GBPS, },
 
+       /*
+        * Devices which choke on SETXFER.  Applies only if both the
+        * device and controller are SATA.
+        */
+       { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
+
        /* End Marker */
        { }
 };
index fa22f94ca4150247b39a0e26fa7541d4cbee4ba4..79711b64054bde8d3d5815fc09aeca08ad3bf00d 100644 (file)
@@ -2327,7 +2327,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
        struct ata_port *ap = link->ap;
        struct ata_link *slave = ap->slave_link;
        struct ata_eh_context *ehc = &link->eh_context;
-       struct ata_eh_context *sehc = &slave->eh_context;
+       struct ata_eh_context *sehc = slave ? &slave->eh_context : NULL;
        unsigned int *classes = ehc->classes;
        unsigned int lflags = link->flags;
        int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
@@ -2517,6 +2517,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
 
                        ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
                        rc = ata_do_reset(link, reset, classes, deadline, true);
+                       if (rc) {
+                               failed_link = link;
+                               goto fail;
+                       }
                }
        } else {
                if (verbose)
index 4b27617be26da7ecfadd5ac53476237348559310..5702affcb3254458f8c4afa28fa152a44a875455 100644 (file)
@@ -26,9 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
 
-#include <mach/at91sam9260_matrix.h>
 #include <mach/at91sam9_smc.h>
-#include <mach/at91sam9260.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 
@@ -44,65 +42,62 @@ struct at91_ide_info {
        unsigned long mode;
        unsigned int cs;
 
+       struct clk *mck;
+
        void __iomem *ide_addr;
        void __iomem *alt_addr;
 };
 
-const struct ata_timing initial_timing =
+static const struct ata_timing initial_timing =
        {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
 
-static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
+static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
 {
        unsigned long mul;
 
-    /*
-     * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
-     *     x * (f / 1_000_000_000) =
-     *     x * ((f * 65536) / 1_000_000_000) / 65536 =
-     *     x * (((f / 10_000) * 65536) / 100_000) / 65536 =
-     */
+       /*
+       * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
+       *     x * (f / 1_000_000_000) =
+       *     x * ((f * 65536) / 1_000_000_000) / 65536 =
+       *     x * (((f / 10_000) * 65536) / 100_000) / 65536 =
+       */
 
-    mul = (mck_hz / 10000) << 16;
-    mul /= 100000;
+       mul = (mck_hz / 10000) << 16;
+       mul /= 100000;
 
-    return (ns * mul + 65536) >> 16;    /* rounding */
+       return (ns * mul + 65536) >> 16;    /* rounding */
 }
 
 static void set_smc_mode(struct at91_ide_info *info)
 {
-    at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
-    return;
+       at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
+       return;
 }
 
 static void set_smc_timing(struct device *dev,
                struct at91_ide_info *info, const struct ata_timing *ata)
 {
-       int read_cycle, write_cycle, active, recover;
-       int nrd_setup, nrd_pulse, nrd_recover;
-       int nwe_setup, nwe_pulse;
+       unsigned long read_cycle, write_cycle, active, recover;
+       unsigned long nrd_setup, nrd_pulse, nrd_recover;
+       unsigned long nwe_setup, nwe_pulse;
 
-       int ncs_write_setup, ncs_write_pulse;
-       int ncs_read_setup, ncs_read_pulse;
+       unsigned long ncs_write_setup, ncs_write_pulse;
+       unsigned long ncs_read_setup, ncs_read_pulse;
 
-       unsigned int mck_hz;
-       struct clk *mck;
+       unsigned long mck_hz;
 
        read_cycle  = ata->cyc8b;
        nrd_setup   = ata->setup;
        nrd_pulse   = ata->act8b;
        nrd_recover = ata->rec8b;
 
-       mck = clk_get(NULL, "mck");
-       BUG_ON(IS_ERR(mck));
-       mck_hz = clk_get_rate(mck);
+       mck_hz = clk_get_rate(info->mck);
 
        read_cycle  = calc_mck_cycles(read_cycle, mck_hz);
        nrd_setup   = calc_mck_cycles(nrd_setup, mck_hz);
        nrd_pulse   = calc_mck_cycles(nrd_pulse, mck_hz);
        nrd_recover = calc_mck_cycles(nrd_recover, mck_hz);
 
-       clk_put(mck);
-
        active  = nrd_setup + nrd_pulse;
        recover = read_cycle - active;
 
@@ -121,13 +116,13 @@ static void set_smc_timing(struct device *dev,
        ncs_write_setup = ncs_read_setup;
        ncs_write_pulse = ncs_read_pulse;
 
-       dev_dbg(dev, "ATA timings: nrd_setup = %d nrd_pulse = %d nrd_cycle = %d\n",
+       dev_dbg(dev, "ATA timings: nrd_setup = %lu nrd_pulse = %lu nrd_cycle = %lu\n",
                        nrd_setup, nrd_pulse, read_cycle);
-       dev_dbg(dev, "ATA timings: nwe_setup = %d nwe_pulse = %d nwe_cycle = %d\n",
+       dev_dbg(dev, "ATA timings: nwe_setup = %lu nwe_pulse = %lu nwe_cycle = %lu\n",
                        nwe_setup, nwe_pulse, write_cycle);
-       dev_dbg(dev, "ATA timings: ncs_read_setup = %d ncs_read_pulse = %d\n",
+       dev_dbg(dev, "ATA timings: ncs_read_setup = %lu ncs_read_pulse = %lu\n",
                        ncs_read_setup, ncs_read_pulse);
-       dev_dbg(dev, "ATA timings: ncs_write_setup = %d ncs_write_pulse = %d\n",
+       dev_dbg(dev, "ATA timings: ncs_write_setup = %lu ncs_write_pulse = %lu\n",
                        ncs_write_setup, ncs_write_pulse);
 
        at91_sys_write(AT91_SMC_SETUP(info->cs),
@@ -217,6 +212,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev)
        struct resource *mem_res;
        struct ata_host *host;
        struct ata_port *ap;
+
        int irq_flags = 0;
        int irq = 0;
        int ret;
@@ -261,6 +257,13 @@ static int __devinit pata_at91_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       info->mck = clk_get(NULL, "mck");
+
+       if (IS_ERR(info->mck)) {
+               dev_err(dev, "failed to get access to mck clock\n");
+               return -ENODEV;
+       }
+
        info->cs    = board->chipselect;
        info->mode  = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
                AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT |
@@ -304,6 +307,7 @@ err_alt_ioremap:
        devm_iounmap(dev, info->ide_addr);
 
 err_ide_ioremap:
+       clk_put(info->mck);
        kfree(info);
 
        return ret;
@@ -312,11 +316,12 @@ err_ide_ioremap:
 static int __devexit pata_at91_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
-       struct at91_ide_info *info = host->private_data;
+       struct at91_ide_info *info;
        struct device *dev = &pdev->dev;
 
        if (!host)
                return 0;
+       info = host->private_data;
 
        ata_host_detach(host);
 
@@ -325,6 +330,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev)
 
        devm_iounmap(dev, info->ide_addr);
        devm_iounmap(dev, info->alt_addr);
+       clk_put(info->mck);
 
        kfree(info);
        return 0;
index 8d9343accf3ca2bf937ab358fe1afdcd99224100..abdd19fe990a36172c5364dee588c1045bd65a2d 100644 (file)
@@ -653,7 +653,8 @@ static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
 
                ap = host->ports[i];
                ocd = ap->dev->platform_data;
-               if (!ap || (ap->flags & ATA_FLAG_DISABLED))
+
+               if (ap->flags & ATA_FLAG_DISABLED)
                        continue;
 
                ocd = ap->dev->platform_data;
index f4d009ed50aceb10b04e49b6ec9a9c7f1dff6cf6..dc99e26f8e5ba8c5d1a5635de6816d2a868a44bb 100644 (file)
@@ -411,6 +411,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
        PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("CNF   ", "CD-ROM", 0x46d7db81, 0x66536591),
        PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
        PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
        PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
index 23714aefb8256d742c56858b9a57e9614ecfb8c1..c19417e02208f3c500c269fcdf5b8846ff19464b 100644 (file)
@@ -2514,7 +2514,7 @@ static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
        char *when = "idle";
 
        ata_ehi_clear_desc(ehi);
-       if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+       if (ap->flags & ATA_FLAG_DISABLED) {
                when = "disabled";
        } else if (edma_was_enabled) {
                when = "EDMA enabled";
index 030ec079b184ec592cae99164a91fcca8b5b9075..35bd5cc7f2854b04654039ef4025f6ccfff4a739 100644 (file)
@@ -532,7 +532,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
                struct ata_port *ap = host->ports[i];
                u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
 
-               if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+               if (unlikely(ap->flags & ATA_FLAG_DISABLED))
                        continue;
 
                /* turn off SATA_IRQ if not supported */
index e8beb8e5b6264232dbfc0ea2dc7ae95d76f5af64..05dd307e8f024038bfe6e9d762e3dff1dd6281ee 100644 (file)
@@ -428,6 +428,9 @@ int devres_release_all(struct device *dev)
 {
        unsigned long flags;
 
+       /* Looks like an uninitialized device structure */
+       if (WARN_ON(dev->devres_head.next == NULL))
+               return -ENODEV;
        spin_lock_irqsave(&dev->devres_lock, flags);
        return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
                             flags);
index fc466531260e9a3fcdf82d7a5a323f8dd949e6de..7376367bcb8053dec4951945f916d47c882fd59a 100644 (file)
@@ -180,7 +180,6 @@ static ssize_t firmware_loading_store(struct device *dev,
                                goto err;
                        }
                        /* Pages will be freed by vfree() */
-                       fw_priv->pages = NULL;
                        fw_priv->page_array_size = 0;
                        fw_priv->nr_pages = 0;
                        complete(&fw_priv->completion);
@@ -217,8 +216,10 @@ firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                ret_count = -ENODEV;
                goto out;
        }
-       if (offset > fw->size)
-               return 0;
+       if (offset > fw->size) {
+               ret_count = 0;
+               goto out;
+       }
        if (count > fw->size - offset)
                count = fw->size - offset;
 
index 79a9ae5238acc1b9fa06a2fed1ed70d2440a9416..0d903909af7e5366126baaa049d35c5ea26fe6b5 100644 (file)
@@ -275,9 +275,9 @@ int sysdev_register(struct sys_device *sysdev)
                                drv->add(sysdev);
                }
                mutex_unlock(&sysdev_drivers_lock);
+               kobject_uevent(&sysdev->kobj, KOBJ_ADD);
        }
 
-       kobject_uevent(&sysdev->kobj, KOBJ_ADD);
        return error;
 }
 
index 668dc234b8e22d5b09950950914398d6f1f61766..1e6b7c14f697c58b7ad5f551e6f947d2fe7719a2 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
index bb72ada9f074588e49796267b59600f848a615be..1d886e079c588e70951965b7a67192b962967c16 100644 (file)
@@ -298,6 +298,22 @@ config BLK_DEV_NBD
 
          If unsure, say N.
 
+config BLK_DEV_OSD
+       tristate "OSD object-as-blkdev support"
+       depends on SCSI_OSD_ULD
+       ---help---
+         Saying Y or M here will allow the exporting of a single SCSI
+         OSD (object-based storage) object as a Linux block device.
+
+         For example, if you create a 2G object on an OSD device,
+         you can then use this module to present that 2G object as
+         a Linux block device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called osdblk.
+
+         If unsure, say N.
+
 config BLK_DEV_SX8
        tristate "Promise SATA SX8 support"
        depends on PCI
index 7755a5e2a85e3b5a7ffcfe1544ce507df050764d..cdaa3f8fddf03f324bfe72b92b2ad884e5e1af0a 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_XILINX_SYSACE)   += xsysace.o
 obj-$(CONFIG_CDROM_PKTCDVD)    += pktcdvd.o
 obj-$(CONFIG_MG_DISK)          += mg_disk.o
 obj-$(CONFIG_SUNVDC)           += sunvdc.o
+obj-$(CONFIG_BLK_DEV_OSD)      += osdblk.o
 
 obj-$(CONFIG_BLK_DEV_UMEM)     += umem.o
 obj-$(CONFIG_BLK_DEV_NBD)      += nbd.o
index f5e7180d7f47d050ed0e39a37ad748054658b52b..3ff02941b3dd40c57ca9a2cc56d7442c5cd538cb 100644 (file)
@@ -1627,7 +1627,7 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
                                drive, dtp->blocks, dtp->spt, dtp->stretch);
 
                /* sanity check */
-               if (!dtp || setprm.track != dtp->blocks/dtp->spt/2 ||
+               if (setprm.track != dtp->blocks/dtp->spt/2 ||
                    setprm.head != 2) {
                        redo_fd_request();
                        return -EINVAL;
index 65a0655e7fc8451380d34decf3b04025776f9d0c..a52cc7fe45ea12d4e3d7742615ed9904013e0f10 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <linux/fs.h>
index 801f4ab83302556e9b48f1ddf139201a05e8c304..5757188cd1fb33393e830adf89313857146ce752 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/loop.h>
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
new file mode 100644 (file)
index 0000000..13c1aee
--- /dev/null
@@ -0,0 +1,701 @@
+
+/*
+   osdblk.c -- Export a single SCSI OSD object as a Linux block device
+
+
+   Copyright 2009 Red Hat, 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.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   Instructions for use
+   --------------------
+
+   1) Map a Linux block device to an existing OSD object.
+
+      In this example, we will use partition id 1234, object id 5678,
+      OSD device /dev/osd1.
+
+      $ echo "1234 5678 /dev/osd1" > /sys/class/osdblk/add
+
+
+   2) List all active blkdev<->object mappings.
+
+      In this example, we have performed step #1 twice, creating two blkdevs,
+      mapped to two separate OSD objects.
+
+      $ cat /sys/class/osdblk/list
+      0 174 1234 5678 /dev/osd1
+      1 179 1994 897123 /dev/osd0
+
+      The columns, in order, are:
+      - blkdev unique id
+      - blkdev assigned major
+      - OSD object partition id
+      - OSD object id
+      - OSD device
+
+
+   3) Remove an active blkdev<->object mapping.
+
+      In this example, we remove the mapping with blkdev unique id 1.
+
+      $ echo 1 > /sys/class/osdblk/remove
+
+
+   NOTE:  The actual creation and deletion of OSD objects is outside the scope
+   of this driver.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_attributes.h>
+#include <scsi/osd_sec.h>
+#include <scsi/scsi_device.h>
+
+#define DRV_NAME "osdblk"
+#define PFX DRV_NAME ": "
+
+/* #define _OSDBLK_DEBUG */
+#ifdef _OSDBLK_DEBUG
+#define OSDBLK_DEBUG(fmt, a...) \
+       printk(KERN_NOTICE "osdblk @%s:%d: " fmt, __func__, __LINE__, ##a)
+#else
+#define OSDBLK_DEBUG(fmt, a...) \
+       do { if (0) printk(fmt, ##a); } while (0)
+#endif
+
+MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>");
+MODULE_DESCRIPTION("block device inside an OSD object osdblk.ko");
+MODULE_LICENSE("GPL");
+
+struct osdblk_device;
+
+enum {
+       OSDBLK_MINORS_PER_MAJOR = 256,          /* max minors per blkdev */
+       OSDBLK_MAX_REQ          = 32,           /* max parallel requests */
+       OSDBLK_OP_TIMEOUT       = 4 * 60,       /* sync OSD req timeout */
+};
+
+struct osdblk_request {
+       struct request          *rq;            /* blk layer request */
+       struct bio              *bio;           /* cloned bio */
+       struct osdblk_device    *osdev;         /* associated blkdev */
+};
+
+struct osdblk_device {
+       int                     id;             /* blkdev unique id */
+
+       int                     major;          /* blkdev assigned major */
+       struct gendisk          *disk;          /* blkdev's gendisk and rq */
+       struct request_queue    *q;
+
+       struct osd_dev          *osd;           /* associated OSD */
+
+       char                    name[32];       /* blkdev name, e.g. osdblk34 */
+
+       spinlock_t              lock;           /* queue lock */
+
+       struct osd_obj_id       obj;            /* OSD partition, obj id */
+       uint8_t                 obj_cred[OSD_CAP_LEN]; /* OSD cred */
+
+       struct osdblk_request   req[OSDBLK_MAX_REQ]; /* request table */
+
+       struct list_head        node;
+
+       char                    osd_path[0];    /* OSD device path */
+};
+
+static struct class *class_osdblk;             /* /sys/class/osdblk */
+static DEFINE_MUTEX(ctl_mutex);        /* Serialize open/close/setup/teardown */
+static LIST_HEAD(osdblkdev_list);
+
+static struct block_device_operations osdblk_bd_ops = {
+       .owner          = THIS_MODULE,
+};
+
+static const struct osd_attr g_attr_logical_length = ATTR_DEF(
+       OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
+
+static void osdblk_make_credential(u8 cred_a[OSD_CAP_LEN],
+                                  const struct osd_obj_id *obj)
+{
+       osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
+}
+
+/* copied from exofs; move to libosd? */
+/*
+ * Perform a synchronous OSD operation.  copied from exofs; move to libosd?
+ */
+static int osd_sync_op(struct osd_request *or, int timeout, uint8_t *credential)
+{
+       int ret;
+
+       or->timeout = timeout;
+       ret = osd_finalize_request(or, 0, credential, NULL);
+       if (ret)
+               return ret;
+
+       ret = osd_execute_request(or);
+
+       /* osd_req_decode_sense(or, ret); */
+       return ret;
+}
+
+/*
+ * Perform an asynchronous OSD operation.  copied from exofs; move to libosd?
+ */
+static int osd_async_op(struct osd_request *or, osd_req_done_fn *async_done,
+                  void *caller_context, u8 *cred)
+{
+       int ret;
+
+       ret = osd_finalize_request(or, 0, cred, NULL);
+       if (ret)
+               return ret;
+
+       ret = osd_execute_request_async(or, async_done, caller_context);
+
+       return ret;
+}
+
+/* copied from exofs; move to libosd? */
+static int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
+{
+       struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
+       void *iter = NULL;
+       int nelem;
+
+       do {
+               nelem = 1;
+               osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter);
+               if ((cur_attr.attr_page == attr->attr_page) &&
+                   (cur_attr.attr_id == attr->attr_id)) {
+                       attr->len = cur_attr.len;
+                       attr->val_ptr = cur_attr.val_ptr;
+                       return 0;
+               }
+       } while (iter);
+
+       return -EIO;
+}
+
+static int osdblk_get_obj_size(struct osdblk_device *osdev, u64 *size_out)
+{
+       struct osd_request *or;
+       struct osd_attr attr;
+       int ret;
+
+       /* start request */
+       or = osd_start_request(osdev->osd, GFP_KERNEL);
+       if (!or)
+               return -ENOMEM;
+
+       /* create a get-attributes(length) request */
+       osd_req_get_attributes(or, &osdev->obj);
+
+       osd_req_add_get_attr_list(or, &g_attr_logical_length, 1);
+
+       /* execute op synchronously */
+       ret = osd_sync_op(or, OSDBLK_OP_TIMEOUT, osdev->obj_cred);
+       if (ret)
+               goto out;
+
+       /* extract length from returned attribute info */
+       attr = g_attr_logical_length;
+       ret = extract_attr_from_req(or, &attr);
+       if (ret)
+               goto out;
+
+       *size_out = get_unaligned_be64(attr.val_ptr);
+
+out:
+       osd_end_request(or);
+       return ret;
+
+}
+
+static void osdblk_osd_complete(struct osd_request *or, void *private)
+{
+       struct osdblk_request *orq = private;
+       struct osd_sense_info osi;
+       int ret = osd_req_decode_sense(or, &osi);
+
+       if (ret) {
+               ret = -EIO;
+               OSDBLK_DEBUG("osdblk_osd_complete with err=%d\n", ret);
+       }
+
+       /* complete OSD request */
+       osd_end_request(or);
+
+       /* complete request passed to osdblk by block layer */
+       __blk_end_request_all(orq->rq, ret);
+}
+
+static void bio_chain_put(struct bio *chain)
+{
+       struct bio *tmp;
+
+       while (chain) {
+               tmp = chain;
+               chain = chain->bi_next;
+
+               bio_put(tmp);
+       }
+}
+
+static struct bio *bio_chain_clone(struct bio *old_chain, gfp_t gfpmask)
+{
+       struct bio *tmp, *new_chain = NULL, *tail = NULL;
+
+       while (old_chain) {
+               tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
+               if (!tmp)
+                       goto err_out;
+
+               __bio_clone(tmp, old_chain);
+               tmp->bi_bdev = NULL;
+               gfpmask &= ~__GFP_WAIT;
+               tmp->bi_next = NULL;
+
+               if (!new_chain)
+                       new_chain = tail = tmp;
+               else {
+                       tail->bi_next = tmp;
+                       tail = tmp;
+               }
+
+               old_chain = old_chain->bi_next;
+       }
+
+       return new_chain;
+
+err_out:
+       OSDBLK_DEBUG("bio_chain_clone with err\n");
+       bio_chain_put(new_chain);
+       return NULL;
+}
+
+static void osdblk_rq_fn(struct request_queue *q)
+{
+       struct osdblk_device *osdev = q->queuedata;
+
+       while (1) {
+               struct request *rq;
+               struct osdblk_request *orq;
+               struct osd_request *or;
+               struct bio *bio;
+               bool do_write, do_flush;
+
+               /* peek at request from block layer */
+               rq = blk_fetch_request(q);
+               if (!rq)
+                       break;
+
+               /* filter out block requests we don't understand */
+               if (!blk_fs_request(rq) && !blk_barrier_rq(rq)) {
+                       blk_end_request_all(rq, 0);
+                       continue;
+               }
+
+               /* deduce our operation (read, write, flush) */
+               /* I wish the block layer simplified cmd_type/cmd_flags/cmd[]
+                * into a clearly defined set of RPC commands:
+                * read, write, flush, scsi command, power mgmt req,
+                * driver-specific, etc.
+                */
+
+               do_flush = (rq->special == (void *) 0xdeadbeefUL);
+               do_write = (rq_data_dir(rq) == WRITE);
+
+               if (!do_flush) { /* osd_flush does not use a bio */
+                       /* a bio clone to be passed down to OSD request */
+                       bio = bio_chain_clone(rq->bio, GFP_ATOMIC);
+                       if (!bio)
+                               break;
+               } else
+                       bio = NULL;
+
+               /* alloc internal OSD request, for OSD command execution */
+               or = osd_start_request(osdev->osd, GFP_ATOMIC);
+               if (!or) {
+                       bio_chain_put(bio);
+                       OSDBLK_DEBUG("osd_start_request with err\n");
+                       break;
+               }
+
+               orq = &osdev->req[rq->tag];
+               orq->rq = rq;
+               orq->bio = bio;
+               orq->osdev = osdev;
+
+               /* init OSD command: flush, write or read */
+               if (do_flush)
+                       osd_req_flush_object(or, &osdev->obj,
+                                            OSD_CDB_FLUSH_ALL, 0, 0);
+               else if (do_write)
+                       osd_req_write(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
+                                     bio, blk_rq_bytes(rq));
+               else
+                       osd_req_read(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
+                                    bio, blk_rq_bytes(rq));
+
+               OSDBLK_DEBUG("%s 0x%x bytes at 0x%llx\n",
+                       do_flush ? "flush" : do_write ?
+                               "write" : "read", blk_rq_bytes(rq),
+                       blk_rq_pos(rq) * 512ULL);
+
+               /* begin OSD command execution */
+               if (osd_async_op(or, osdblk_osd_complete, orq,
+                                osdev->obj_cred)) {
+                       osd_end_request(or);
+                       blk_requeue_request(q, rq);
+                       bio_chain_put(bio);
+                       OSDBLK_DEBUG("osd_execute_request_async with err\n");
+                       break;
+               }
+
+               /* remove the special 'flush' marker, now that the command
+                * is executing
+                */
+               rq->special = NULL;
+       }
+}
+
+static void osdblk_prepare_flush(struct request_queue *q, struct request *rq)
+{
+       /* add driver-specific marker, to indicate that this request
+        * is a flush command
+        */
+       rq->special = (void *) 0xdeadbeefUL;
+}
+
+static void osdblk_free_disk(struct osdblk_device *osdev)
+{
+       struct gendisk *disk = osdev->disk;
+
+       if (!disk)
+               return;
+
+       if (disk->flags & GENHD_FL_UP)
+               del_gendisk(disk);
+       if (disk->queue)
+               blk_cleanup_queue(disk->queue);
+       put_disk(disk);
+}
+
+static int osdblk_init_disk(struct osdblk_device *osdev)
+{
+       struct gendisk *disk;
+       struct request_queue *q;
+       int rc;
+       u64 obj_size = 0;
+
+       /* contact OSD, request size info about the object being mapped */
+       rc = osdblk_get_obj_size(osdev, &obj_size);
+       if (rc)
+               return rc;
+
+       /* create gendisk info */
+       disk = alloc_disk(OSDBLK_MINORS_PER_MAJOR);
+       if (!disk)
+               return -ENOMEM;
+
+       sprintf(disk->disk_name, DRV_NAME "%d", osdev->id);
+       disk->major = osdev->major;
+       disk->first_minor = 0;
+       disk->fops = &osdblk_bd_ops;
+       disk->private_data = osdev;
+
+       /* init rq */
+       q = blk_init_queue(osdblk_rq_fn, &osdev->lock);
+       if (!q) {
+               put_disk(disk);
+               return -ENOMEM;
+       }
+
+       /* switch queue to TCQ mode; allocate tag map */
+       rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL);
+       if (rc) {
+               blk_cleanup_queue(q);
+               put_disk(disk);
+               return rc;
+       }
+
+       /* Set our limits to the lower device limits, because osdblk cannot
+        * sleep when allocating a lower-request and therefore cannot be
+        * bouncing.
+        */
+       blk_queue_stack_limits(q, osd_request_queue(osdev->osd));
+
+       blk_queue_prep_rq(q, blk_queue_start_tag);
+       blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, osdblk_prepare_flush);
+
+       disk->queue = q;
+
+       q->queuedata = osdev;
+
+       osdev->disk = disk;
+       osdev->q = q;
+
+       /* finally, announce the disk to the world */
+       set_capacity(disk, obj_size / 512ULL);
+       add_disk(disk);
+
+       printk(KERN_INFO "%s: Added of size 0x%llx\n",
+               disk->disk_name, (unsigned long long)obj_size);
+
+       return 0;
+}
+
+/********************************************************************
+ * /sys/class/osdblk/
+ *                   add       map OSD object to blkdev
+ *                   remove    unmap OSD object
+ *                   list      show mappings
+ *******************************************************************/
+
+static void class_osdblk_release(struct class *cls)
+{
+       kfree(cls);
+}
+
+static ssize_t class_osdblk_list(struct class *c, char *data)
+{
+       int n = 0;
+       struct list_head *tmp;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               struct osdblk_device *osdev;
+
+               osdev = list_entry(tmp, struct osdblk_device, node);
+
+               n += sprintf(data+n, "%d %d %llu %llu %s\n",
+                       osdev->id,
+                       osdev->major,
+                       osdev->obj.partition,
+                       osdev->obj.id,
+                       osdev->osd_path);
+       }
+
+       mutex_unlock(&ctl_mutex);
+       return n;
+}
+
+static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count)
+{
+       struct osdblk_device *osdev;
+       ssize_t rc;
+       int irc, new_id = 0;
+       struct list_head *tmp;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       /* new osdblk_device object */
+       osdev = kzalloc(sizeof(*osdev) + strlen(buf) + 1, GFP_KERNEL);
+       if (!osdev) {
+               rc = -ENOMEM;
+               goto err_out_mod;
+       }
+
+       /* static osdblk_device initialization */
+       spin_lock_init(&osdev->lock);
+       INIT_LIST_HEAD(&osdev->node);
+
+       /* generate unique id: find highest unique id, add one */
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               struct osdblk_device *osdev;
+
+               osdev = list_entry(tmp, struct osdblk_device, node);
+               if (osdev->id > new_id)
+                       new_id = osdev->id + 1;
+       }
+
+       osdev->id = new_id;
+
+       /* add to global list */
+       list_add_tail(&osdev->node, &osdblkdev_list);
+
+       mutex_unlock(&ctl_mutex);
+
+       /* parse add command */
+       if (sscanf(buf, "%llu %llu %s", &osdev->obj.partition, &osdev->obj.id,
+                  osdev->osd_path) != 3) {
+               rc = -EINVAL;
+               goto err_out_slot;
+       }
+
+       /* initialize rest of new object */
+       sprintf(osdev->name, DRV_NAME "%d", osdev->id);
+
+       /* contact requested OSD */
+       osdev->osd = osduld_path_lookup(osdev->osd_path);
+       if (IS_ERR(osdev->osd)) {
+               rc = PTR_ERR(osdev->osd);
+               goto err_out_slot;
+       }
+
+       /* build OSD credential */
+       osdblk_make_credential(osdev->obj_cred, &osdev->obj);
+
+       /* register our block device */
+       irc = register_blkdev(0, osdev->name);
+       if (irc < 0) {
+               rc = irc;
+               goto err_out_osd;
+       }
+
+       osdev->major = irc;
+
+       /* set up and announce blkdev mapping */
+       rc = osdblk_init_disk(osdev);
+       if (rc)
+               goto err_out_blkdev;
+
+       return count;
+
+err_out_blkdev:
+       unregister_blkdev(osdev->major, osdev->name);
+err_out_osd:
+       osduld_put_device(osdev->osd);
+err_out_slot:
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       list_del_init(&osdev->node);
+       mutex_unlock(&ctl_mutex);
+
+       kfree(osdev);
+err_out_mod:
+       OSDBLK_DEBUG("Error adding device %s\n", buf);
+       module_put(THIS_MODULE);
+       return rc;
+}
+
+static ssize_t class_osdblk_remove(struct class *c, const char *buf,
+                                       size_t count)
+{
+       struct osdblk_device *osdev = NULL;
+       int target_id, rc;
+       unsigned long ul;
+       struct list_head *tmp;
+
+       rc = strict_strtoul(buf, 10, &ul);
+       if (rc)
+               return rc;
+
+       /* convert to int; abort if we lost anything in the conversion */
+       target_id = (int) ul;
+       if (target_id != ul)
+               return -EINVAL;
+
+       /* remove object from list immediately */
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &osdblkdev_list) {
+               osdev = list_entry(tmp, struct osdblk_device, node);
+               if (osdev->id == target_id) {
+                       list_del_init(&osdev->node);
+                       break;
+               }
+               osdev = NULL;
+       }
+
+       mutex_unlock(&ctl_mutex);
+
+       if (!osdev)
+               return -ENOENT;
+
+       /* clean up and free blkdev and associated OSD connection */
+       osdblk_free_disk(osdev);
+       unregister_blkdev(osdev->major, osdev->name);
+       osduld_put_device(osdev->osd);
+       kfree(osdev);
+
+       /* release module ref */
+       module_put(THIS_MODULE);
+
+       return count;
+}
+
+static struct class_attribute class_osdblk_attrs[] = {
+       __ATTR(add,     0200, NULL, class_osdblk_add),
+       __ATTR(remove,  0200, NULL, class_osdblk_remove),
+       __ATTR(list,    0444, class_osdblk_list, NULL),
+       __ATTR_NULL
+};
+
+static int osdblk_sysfs_init(void)
+{
+       int ret = 0;
+
+       /*
+        * create control files in sysfs
+        * /sys/class/osdblk/...
+        */
+       class_osdblk = kzalloc(sizeof(*class_osdblk), GFP_KERNEL);
+       if (!class_osdblk)
+               return -ENOMEM;
+
+       class_osdblk->name = DRV_NAME;
+       class_osdblk->owner = THIS_MODULE;
+       class_osdblk->class_release = class_osdblk_release;
+       class_osdblk->class_attrs = class_osdblk_attrs;
+
+       ret = class_register(class_osdblk);
+       if (ret) {
+               kfree(class_osdblk);
+               class_osdblk = NULL;
+               printk(PFX "failed to create class osdblk\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void osdblk_sysfs_cleanup(void)
+{
+       if (class_osdblk)
+               class_destroy(class_osdblk);
+       class_osdblk = NULL;
+}
+
+static int __init osdblk_init(void)
+{
+       int rc;
+
+       rc = osdblk_sysfs_init();
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static void __exit osdblk_exit(void)
+{
+       osdblk_sysfs_cleanup();
+}
+
+module_init(osdblk_init);
+module_exit(osdblk_exit);
+
index 83650e00632d80b6837678355fbac3c50c6d9a94..99a506f619b71bcadac21608b5969931441e05cf 100644 (file)
@@ -1372,8 +1372,10 @@ try_next_bio:
        wakeup = (pd->write_congestion_on > 0
                        && pd->bio_queue_size <= pd->write_congestion_off);
        spin_unlock(&pd->lock);
-       if (wakeup)
-               clear_bdi_congested(&pd->disk->queue->backing_dev_info, WRITE);
+       if (wakeup) {
+               clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+                                       BLK_RW_ASYNC);
+       }
 
        pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
        pkt_set_state(pkt, PACKET_WAITING_STATE);
@@ -2592,10 +2594,10 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
        spin_lock(&pd->lock);
        if (pd->write_congestion_on > 0
            && pd->bio_queue_size >= pd->write_congestion_on) {
-               set_bdi_congested(&q->backing_dev_info, WRITE);
+               set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
                do {
                        spin_unlock(&pd->lock);
-                       congestion_wait(WRITE, HZ);
+                       congestion_wait(BLK_RW_ASYNC, HZ);
                        spin_lock(&pd->lock);
                } while(pd->bio_queue_size > pd->write_congestion_off);
        }
index 43db3ea15b54936da4502526602c117876bd67fc..aa1a3d5a3e2bc3f202bb695da2624f4d8cfd03b5 100644 (file)
@@ -213,7 +213,7 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
         * Only allow the generic SCSI ioctls if the host can support it.
         */
        if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
-               return -ENOIOCTLCMD;
+               return -ENOTTY;
 
        return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
 }
@@ -360,6 +360,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
        blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
 
+       /* No need to bounce any requests */
+       blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);
+
        /* No real sector limit. */
        blk_queue_max_sectors(vblk->disk->queue, -1U);
 
@@ -424,7 +427,12 @@ static unsigned int features[] = {
        VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY
 };
 
-static struct virtio_driver virtio_blk = {
+/*
+ * virtio_blk causes spurious section mismatch warning by
+ * simultaneously referring to a __devinit and a __devexit function.
+ * Use __refdata to avoid this warning.
+ */
+static struct virtio_driver __refdata virtio_blk = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
index 4575171e5beb1bd754e0fe0ba11600b0fce4ea3f..b2590409f25efb1911dc8e87a4d88c2dc0b3d719 100644 (file)
@@ -374,7 +374,7 @@ err:
 static void __exit z2_exit(void)
 {
     int i, j;
-    blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256);
+    blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT);
     unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
     del_gendisk(z2ram_gendisk);
     put_disk(z2ram_gendisk);
index 1df9dda2e377d8415366ae43fb1c44e57e2ed9d2..d5cde6d86f891a2c01a47cdfbdbe43772e6de86d 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
index 72429b6b2fa831e8ce925145398acfbb7aa66170..6c32fbf071648931374bfc6fa699d6ba37a523f1 100644 (file)
@@ -81,6 +81,7 @@ static char *serial_version = "4.30";
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 
index f3366d3f06cfe404cdfe94b6d3393c55b7b05886..2dafc2da06488f631b1b6937b287440d8a1417bd 100644 (file)
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
index abef1f7d84fefb03ef23ffc90417d173aea7ceef..ff647ca1c4895d9f08049ea840496b86b40fbf28 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
index 94e7e3c8c05ad3f0720aaae3d6df588eebd2d50b..d97779ef72cb2846dabe8487ebf4cc0b4c7c6bf3 100644 (file)
@@ -552,7 +552,7 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
        struct hvc_struct *hp = tty->driver_data;
 
        if (!hp)
-               return -1;
+               return 0;
        return hp->n_outbuf;
 }
 
index 621d1184673c72eac2779338c620a549dd8f470a..4f1f4cd670dac7dcd252d088ee2760d2977df1f3 100644 (file)
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
index 0c999f5bb3db6df69e0062609e9f82d1c0ee8955..ab2f3349c5c4cc9dc13e3021307a3ede3ddf9a92 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
index 65b6ff2442c6df4edfd839b37752ded8340df9c9..dd0083bbb64addaea9b286ac8d5a914a474625ea 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index 52d953eb30c3d6872eb6e4d3b3710ba7578e272c..dbf8d52f31d02d743b0436abcc871104bdf7e588 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
index 1c43c8cdee259f18d3ffbf0e063be81dc5c2f3f2..c68118efad844940e7977f4e30afa5f3c694977d 100644 (file)
@@ -97,6 +97,7 @@
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <linux/if.h>
index 2e99158ebb8a6e7922a1ac0c0f97c0a06b49f338..6934025a1ac10d5e094c0b9df10ec88ff0f40468 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>      /* used in new tty drivers */
index 94a5d5020abcec935e08d6bc74180a249ea58423..973be2f441951ed0e68d658c1192c94524f33aff 100644 (file)
@@ -1331,9 +1331,6 @@ handle_newline:
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
 {
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
        if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
                kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
 }
@@ -1586,6 +1583,7 @@ static int n_tty_open(struct tty_struct *tty)
 
 static inline int input_available_p(struct tty_struct *tty, int amt)
 {
+       tty_flush_to_ldisc(tty);
        if (tty->icanon) {
                if (tty->canon_data)
                        return 1;
index 574f1c79b6e637ededd5a4708651bc7902aea960..ec58d8c387ff2303f67db428622f68b7eff76057 100644 (file)
@@ -828,7 +828,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        struct port *port = &dc->port[index];
        void __iomem *addr = port->dl_addr[port->toggle_dl];
        struct tty_struct *tty = tty_port_tty_get(&port->port);
-       int i;
+       int i, ret;
 
        if (unlikely(!tty)) {
                DBG1("tty not open for port: %d?", index);
@@ -844,12 +844,14 @@ static int receive_data(enum port_type index, struct nozomi *dc)
 
                /* disable interrupt in downlink... */
                disable_transmit_dl(index, dc);
-               return 0;
+               ret = 0;
+               goto put;
        }
 
        if (unlikely(size == 0)) {
                dev_err(&dc->pdev->dev, "size == 0?\n");
-               return 1;
+               ret = 1;
+               goto put;
        }
 
        tty_buffer_request_room(tty, size);
@@ -871,8 +873,10 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        }
 
        set_bit(index, &dc->flip);
+       ret = 1;
+put:
        tty_kref_put(tty);
-       return 1;
+       return ret;
 }
 
 /* Debug for interrupts */
@@ -1862,16 +1866,14 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
 {
        struct port *port = tty->driver_data;
        struct nozomi *dc = get_dc_by_tty(tty);
-       s32 rval;
+       s32 rval = 0;
 
        if (unlikely(!dc || !port)) {
-               rval = -ENODEV;
                goto exit_in_buffer;
        }
 
        if (unlikely(!port->port.count)) {
                dev_err(&dc->pdev->dev, "No tty open?\n");
-               rval = -ENODEV;
                goto exit_in_buffer;
        }
 
index 569f2f7743a78ddc80f4e7714c6456506b8a4995..674b3ab3587d505458fbdb802fc0a7cbcdf7d2eb 100644 (file)
@@ -320,10 +320,10 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
        struct ipw_tty *tty = linux_tty->driver_data;
 
        if (!tty)
-               return -ENODEV;
+               return 0;
 
        if (!tty->open_count)
-               return -EINVAL;
+               return 0;
 
        return tty->tx_bytes_queued;
 }
index 9d1b4f548f677566e8314d27dbbda0824ba67f5c..6e6942c45f5b6cb76d6c1aaf91ed96fee9185ae7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/sysctl.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
index ce81da5b2da9a20079cf46fe64eddcac546b1474..d58c2eb07f07aaad25a568095ccaab7d3e53f686 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 
index 217660451237a79c7cd186d38697bad07f9dbcf8..171711acf5cd33736ebb74d69a6f02983b15bdb3 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 
index 63d5b628477a72bbffb6cb8696a0a4b615ef5725..0e29a23ec4c50be1f2d74b492c91785a8feae2b3 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index f1f24f0ee26f4281392925b0d86b4ad4a5e897af..51e7a46787bea72aa23e93535e4d9ce636b63448 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/interrupt.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index e72be4190a442a6378cca9a68a306b3421dcb06c..268e17f9ec3f50c4586607bb0dd59e76442f3bee 100644 (file)
@@ -87,6 +87,7 @@
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
 #include <linux/serial.h>
+#include <linux/smp_lock.h>
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
@@ -1808,10 +1809,10 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
                if (clear & TIOCM_DTR)
                        port->MSVR &= ~MSVR_DTR;
        }
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
        sx_out(bp, CD186x_CAR, port_No(port));
        sx_out(bp, CD186x_MSVR, port->MSVR);
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        spin_unlock_irqrestore(&port->lock, flags);
        func_exit();
        return 0;
@@ -1832,11 +1833,11 @@ static int sx_send_break(struct tty_struct *tty, int length)
        port->break_length = SPECIALIX_TPS / HZ * length;
        port->COR2 |= COR2_ETC;
        port->IER  |= IER_TXRDY;
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
        sx_out(bp, CD186x_CAR, port_No(port));
        sx_out(bp, CD186x_COR2, port->COR2);
        sx_out(bp, CD186x_IER, port->IER);
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        spin_unlock_irqrestore(&port->lock, flags);
        sx_wait_CCR(bp);
        spin_lock_irqsave(&bp->lock, flags);
@@ -2022,9 +2023,9 @@ static void sx_unthrottle(struct tty_struct *tty)
        if (sx_crtscts(tty))
                port->MSVR |= MSVR_DTR;
        /* Else clause: see remark in "sx_throttle"... */
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
        sx_out(bp, CD186x_CAR, port_No(port));
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        if (I_IXOFF(tty)) {
                spin_unlock_irqrestore(&port->lock, flags);
                sx_wait_CCR(bp);
@@ -2034,9 +2035,9 @@ static void sx_unthrottle(struct tty_struct *tty)
                sx_wait_CCR(bp);
                spin_lock_irqsave(&port->lock, flags);
        }
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
        sx_out(bp, CD186x_MSVR, port->MSVR);
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        spin_unlock_irqrestore(&port->lock, flags);
 
        func_exit();
@@ -2060,10 +2061,10 @@ static void sx_stop(struct tty_struct *tty)
 
        spin_lock_irqsave(&port->lock, flags);
        port->IER &= ~IER_TXRDY;
-       spin_lock_irqsave(&bp->lock, flags);
+       spin_lock(&bp->lock);
        sx_out(bp, CD186x_CAR, port_No(port));
        sx_out(bp, CD186x_IER, port->IER);
-       spin_unlock_irqrestore(&bp->lock, flags);
+       spin_unlock(&bp->lock);
        spin_unlock_irqrestore(&port->lock, flags);
 
        func_exit();
@@ -2088,10 +2089,10 @@ static void sx_start(struct tty_struct *tty)
        spin_lock_irqsave(&port->lock, flags);
        if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
                port->IER |= IER_TXRDY;
-               spin_lock_irqsave(&bp->lock, flags);
+               spin_lock(&bp->lock);
                sx_out(bp, CD186x_CAR, port_No(port));
                sx_out(bp, CD186x_IER, port->IER);
-               spin_unlock_irqrestore(&bp->lock, flags);
+               spin_unlock(&bp->lock);
        }
        spin_unlock_irqrestore(&port->lock, flags);
 
index 518f2a25d91ec6b1a208c6fe233c505a7395aa47..a81ec4fcf6ff4480b9473587d5424b09cb74510e 100644 (file)
 #include <linux/eisa.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/bitops.h>
index afded3a2379c592082e85e373236addce5d9fcd3..813552f14884427ea785b1ac0e2bec080c704a6a 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
index a2e67e6df3a1406697e3482c93689e314bfe0f12..91f20a92fddf2f9afb76dc10b7ab1d86a150954f 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
index 6f727e3c53ade1028d21cf11f364bdcc2fafbed9..8d4a2a8a0a7001ad314fa282c589229ea53d8804 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
index ccdd828adcef2711e2ed91a7c52f38b1a6dca844..b0603b2e56844e38e1e4082eaf20ed115d78b07e 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/poll.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
 #include "tpm.h"
 
index 810ee25d66a48fa5042c84b7f4cf47f0a870ef4e..3108991c5c8b60f312742ca4eaeb37e4c812ad4c 100644 (file)
@@ -461,6 +461,19 @@ static void flush_to_ldisc(struct work_struct *work)
        tty_ldisc_deref(disc);
 }
 
+/**
+ *     tty_flush_to_ldisc
+ *     @tty: tty to push
+ *
+ *     Push the terminal flip buffers to the line discipline.
+ *
+ *     Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+       flush_to_ldisc(&tty->buf.work.work);
+}
+
 /**
  *     tty_flip_buffer_push    -       terminal
  *     @tty: tty to push
index b24f6c6a1ea317c1ccf399eaf2842f281175d70d..ad6ba4ed280853bce299b8bf6aab4d3d53b7c68e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
index 913aa8d3f1c5d1d211934791d0a0a44ccc4e7feb..acd76b767d4c10aac5b540e31a1cd2dddf3c8436 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
@@ -791,17 +790,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
         * N_TTY.
         */
        if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* Avoid racing set_ldisc */
+               /* Avoid racing set_ldisc or tty_ldisc_release */
                mutex_lock(&tty->ldisc_mutex);
-               /* Switch back to N_TTY */
-               tty_ldisc_halt(tty);
-               tty_ldisc_wait_idle(tty);
-               tty_ldisc_reinit(tty);
-               /* At this point we have a closed ldisc and we want to
-                  reopen it. We could defer this to the next open but
-                  it means auditing a lot of other paths so this is a FIXME */
-               WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-               tty_ldisc_enable(tty);
+               if (tty->ldisc) {       /* Not yet closed */
+                       /* Switch back to N_TTY */
+                       tty_ldisc_halt(tty);
+                       tty_ldisc_wait_idle(tty);
+                       tty_ldisc_reinit(tty);
+                       /* At this point we have a closed ldisc and we want to
+                          reopen it. We could defer this to the next open but
+                          it means auditing a lot of other paths so this is
+                          a FIXME */
+                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+                       tty_ldisc_enable(tty);
+               }
                mutex_unlock(&tty->ldisc_mutex);
                tty_reset_termios(tty);
        }
@@ -866,6 +868,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 
        tty_ldisc_wait_idle(tty);
 
+       mutex_lock(&tty->ldisc_mutex);
        /*
         * Now kill off the ldisc
         */
@@ -876,6 +879,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 
        /* Ensure the next open requests the N_TTY ldisc */
        tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
 
        /* This will need doing differently if we need to lock */
        if (o_tty)
index 4e862a75f7ff213bd62022e852a9d485b65adbbf..9769b1149f7602cf9c2c7ea1a3eab70bfad9b0a0 100644 (file)
@@ -267,7 +267,7 @@ int tty_port_block_til_ready(struct tty_port *port,
        if (retval == 0)
                port->flags |= ASYNC_NORMAL_ACTIVE;
        spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
+       return retval;
        
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
index d94d25c12aa87ccacfe12d72ea5e72d4f3f4f93c..c1791a63d99d40c2e1dbe7a4fba6e1f8cfba8c16 100644 (file)
@@ -495,11 +495,15 @@ void vcs_remove_sysfs(int index)
 
 int __init vcs_init(void)
 {
+       unsigned int i;
+
        if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
                panic("unable to get major %d for vcs device", VCS_MAJOR);
        vc_class = class_create(THIS_MODULE, "vc");
 
        device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
        device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+       for (i = 0; i < MIN_NR_CONSOLES; i++)
+               vcs_make_sysfs(i);
        return 0;
 }
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
deleted file mode 100644 (file)
index e69de29..0000000
index d9113b4c76e370bad289b19558958448846a6064..404f4c1ee43145c5429f6639f0454e5a59818f3f 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/mutex.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
+#include <linux/smp_lock.h>
 #include <linux/tiocl.h>
 #include <linux/kbd_kern.h>
 #include <linux/consolemap.h>
@@ -769,14 +770,12 @@ int vc_allocate(unsigned int currcons)    /* return 0 on success */
            visual_init(vc, currcons, 1);
            if (!*vc->vc_uni_pagedir_loc)
                con_set_default_unimap(vc);
-           if (!vc->vc_kmalloced)
-               vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
            if (!vc->vc_screenbuf) {
                kfree(vc);
                vc_cons[currcons].d = NULL;
                return -ENOMEM;
            }
-           vc->vc_kmalloced = 1;
            vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
            vcs_make_sysfs(currcons);
            atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
@@ -912,10 +911,8 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        if (new_scr_end > new_origin)
                scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
                            new_scr_end - new_origin);
-       if (vc->vc_kmalloced)
-               kfree(vc->vc_screenbuf);
+       kfree(vc->vc_screenbuf);
        vc->vc_screenbuf = newscreen;
-       vc->vc_kmalloced = 1;
        vc->vc_screenbuf_size = new_screen_size;
        set_origin(vc);
 
@@ -994,8 +991,7 @@ void vc_deallocate(unsigned int currcons)
                vc->vc_sw->con_deinit(vc);
                put_pid(vc->vt_pid);
                module_put(vc->vc_sw->owner);
-               if (vc->vc_kmalloced)
-                       kfree(vc->vc_screenbuf);
+               kfree(vc->vc_screenbuf);
                if (currcons >= MIN_NR_CONSOLES)
                        kfree(vc);
                vc_cons[currcons].d = NULL;
@@ -2880,7 +2876,6 @@ static int __init con_init(void)
                INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
                visual_init(vc, currcons, 1);
                vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-               vc->vc_kmalloced = 0;
                vc_init(vc, vc->vc_rows, vc->vc_cols,
                        currcons || !vc->vc_sw->con_save_screen);
        }
index 7539bed0f7e07ec315e9dff21a3a0914161afee6..95189f288f8ccffcab9204c9fbeec0cd1357e3a4 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/console.h>
 #include <linux/consolemap.h>
 #include <linux/signal.h>
+#include <linux/smp_lock.h>
 #include <linux/timex.h>
 
 #include <asm/io.h>
index c769ef269fb5833e96b3ac32ece432c4ce1de564..408c2af25d5097c93f41c6fc519bbfbcae0f230f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     cn_queue.c
  *
- * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
index fd336c5a9057a8da729ebd2d3961cbb7b6a4c271..08b2500f21ec1757cd57472326843642e0a2460f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     connector.c
  *
- * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
 #include <net/sock.h>
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
 
 static u32 cn_idx = CN_IDX_CONNECTOR;
index c668ac855f71cf7793e05246b153ce308f9f415d..b90eda8b34409680863edb45bc7b993ed87a1082 100644 (file)
@@ -776,9 +776,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        struct sys_device *cpu_sys_dev;
        unsigned long flags;
        unsigned int j;
-#ifdef CONFIG_SMP
-       struct cpufreq_policy *managed_policy;
-#endif
 
        if (cpu_is_offline(cpu))
                return 0;
@@ -854,6 +851,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 #endif
 
        for_each_cpu(j, policy->cpus) {
+               struct cpufreq_policy *managed_policy;
+
                if (cpu == j)
                        continue;
 
@@ -932,6 +931,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
        /* symlink affected CPUs */
        for_each_cpu(j, policy->cpus) {
+               struct cpufreq_policy *managed_policy;
+
                if (j == cpu)
                        continue;
                if (!cpu_online(j))
index 858fe603722361f4292052952a738f3f9cc4a03e..24964c1d0af9faa2cb3588dae9b09bc1c14bf8ee 100644 (file)
@@ -970,7 +970,7 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
        }
 
        for (cs = 0; cs < pvt->num_dcsm; cs++) {
-               reg = K8_DCSB0 + (cs * 4);
+               reg = K8_DCSM0 + (cs * 4);
                err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
                                        &pvt->dcsm0[cs]);
                if (unlikely(err))
index b70e06133e78791e8dc2f95342e202bbf5d1067f..b16c9a8c03f5d10e5a2f691653fef4604ec5915d 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
index a6f73f1e99d9b839e369861c5b24e4f17279b8aa..3da9cfa31848c0eb37b36f66c7b3ed8607962e2d 100644 (file)
@@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
                if (ret == false)
                        DRM_ERROR("failed to set mode on crtc %p\n", crtc);
        }
+       /* disable the unused connectors while restoring the modesetting */
+       drm_helper_disable_unused_functions(dev);
        return 0;
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
index 2960b6d73456d65b672ad4a7b715976113002859..9903f270e4409c8239add50adc2a3db80ca56623 100644 (file)
@@ -101,6 +101,10 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                        continue;
 
                tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
+               if (tmp == NULL) {
+                       ret = -1;
+                       goto fail;
+               }
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
index 8104ecaea26fbe7170d4c85b41ee0a96e6a0bec4..ffe8f4394d50d71f96411200d9d4d90907bd5f2c 100644 (file)
@@ -134,26 +134,29 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
        BUG_ON((size & (PAGE_SIZE - 1)) != 0);
 
        obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               goto free;
 
        obj->dev = dev;
        obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
-       if (IS_ERR(obj->filp)) {
-               kfree(obj);
-               return NULL;
-       }
+       if (IS_ERR(obj->filp))
+               goto free;
 
        kref_init(&obj->refcount);
        kref_init(&obj->handlecount);
        obj->size = size;
        if (dev->driver->gem_init_object != NULL &&
            dev->driver->gem_init_object(obj) != 0) {
-               fput(obj->filp);
-               kfree(obj);
-               return NULL;
+               goto fput;
        }
        atomic_inc(&dev->object_count);
        atomic_add(obj->size, &dev->object_memory);
        return obj;
+fput:
+       fput(obj->filp);
+free:
+       kfree(obj);
+       return NULL;
 }
 EXPORT_SYMBOL(drm_gem_object_alloc);
 
index 155a5bbce680ac4187f297699644a29317a188e6..55bb8a82d6127cb5d1ec3bea675e0001de593122 100644 (file)
@@ -489,7 +489,7 @@ int drm_put_minor(struct drm_minor **minor_p)
  */
 void drm_put_dev(struct drm_device *dev)
 {
-       struct drm_driver *driver = dev->driver;
+       struct drm_driver *driver;
        struct drm_map_list *r_list, *list_temp;
 
        DRM_DEBUG("\n");
@@ -498,6 +498,7 @@ void drm_put_dev(struct drm_device *dev)
                DRM_ERROR("cleanup called no dev\n");
                return;
        }
+       driver = dev->driver;
 
        drm_vblank_cleanup(dev);
 
index f112c769d5334148683040deef54a3dde80382f8..8c4783180bf653e9a1885b40896c711c074f78d9 100644 (file)
@@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
                return 0;
        }
 
-       printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
+       DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
 
        dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 
@@ -885,8 +885,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
  * some RAM for the framebuffer at early boot.  This code figures out
  * how much was set aside so we can use it for our own purposes.
  */
-static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
-                         unsigned long *preallocated_size)
+static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
+                         uint32_t *preallocated_size)
 {
        struct pci_dev *bridge_dev;
        u16 tmp = 0;
@@ -984,10 +984,11 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
        return 0;
 }
 
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_load_modeset_init(struct drm_device *dev,
+                                 unsigned long prealloc_size,
+                                 unsigned long agp_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long agp_size, prealloc_size;
        int fb_bar = IS_I9XX(dev) ? 2 : 0;
        int ret = 0;
 
@@ -1002,10 +1003,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (IS_I965G(dev) || IS_G33(dev))
                dev_priv->cursor_needs_physical = false;
 
-       ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
-       if (ret)
-               goto out;
-
        /* Basic memrange allocator for stolen space (aka vram) */
        drm_mm_init(&dev_priv->vram, 0, prealloc_size);
 
@@ -1082,6 +1079,44 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
        master->driver_priv = NULL;
 }
 
+static void i915_get_mem_freq(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       if (!IS_IGD(dev))
+               return;
+
+       tmp = I915_READ(CLKCFG);
+
+       switch (tmp & CLKCFG_FSB_MASK) {
+       case CLKCFG_FSB_533:
+               dev_priv->fsb_freq = 533; /* 133*4 */
+               break;
+       case CLKCFG_FSB_800:
+               dev_priv->fsb_freq = 800; /* 200*4 */
+               break;
+       case CLKCFG_FSB_667:
+               dev_priv->fsb_freq =  667; /* 167*4 */
+               break;
+       case CLKCFG_FSB_400:
+               dev_priv->fsb_freq = 400; /* 100*4 */
+               break;
+       }
+
+       switch (tmp & CLKCFG_MEM_MASK) {
+       case CLKCFG_MEM_533:
+               dev_priv->mem_freq = 533;
+               break;
+       case CLKCFG_MEM_667:
+               dev_priv->mem_freq = 667;
+               break;
+       case CLKCFG_MEM_800:
+               dev_priv->mem_freq = 800;
+               break;
+       }
+}
+
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
@@ -1098,6 +1133,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        struct drm_i915_private *dev_priv = dev->dev_private;
        resource_size_t base, size;
        int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+       uint32_t agp_size, prealloc_size;
 
        /* i915 has 4 more counters */
        dev->counters += 4;
@@ -1146,9 +1182,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                         "performance may suffer.\n");
        }
 
+       ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
+       if (ret)
+               goto out_iomapfree;
+
        /* enable GEM by default */
        dev_priv->has_gem = 1;
 
+       if (prealloc_size > agp_size * 3 / 4) {
+               DRM_ERROR("Detected broken video BIOS with %d/%dkB of video "
+                         "memory stolen.\n",
+                         prealloc_size / 1024, agp_size / 1024);
+               DRM_ERROR("Disabling GEM. (try reducing stolen memory or "
+                         "updating the BIOS to fix).\n");
+               dev_priv->has_gem = 0;
+       }
+
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        if (IS_G4X(dev) || IS_IGDNG(dev)) {
@@ -1165,6 +1214,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        goto out_iomapfree;
        }
 
+       i915_get_mem_freq(dev);
+
        /* On the 945G/GM, the chipset reports the MSI capability on the
         * integrated graphics even though the support isn't actually there
         * according to the published specs.  It doesn't appear to function
@@ -1180,6 +1231,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                pci_enable_msi(dev->pdev);
 
        spin_lock_init(&dev_priv->user_irq_lock);
+       spin_lock_init(&dev_priv->error_lock);
        dev_priv->user_irq_refcount = 0;
 
        ret = drm_vblank_init(dev, I915_NUM_PIPE);
@@ -1190,7 +1242,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev);
+               ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
                if (ret < 0) {
                        DRM_ERROR("failed to init modeset\n");
                        goto out_rmmap;
index e3cb4025e323c6c7d097ca3dd144deb389f7675f..fc4b68aa2d056e9c8b9256860c38b4ac2175f529 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "drm_pciids.h"
 #include <linux/console.h>
+#include "drm_crtc_helper.h"
 
 static unsigned int i915_modeset = -1;
 module_param_named(modeset, i915_modeset, int, 0400);
@@ -57,8 +58,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!dev || !dev_priv) {
-               printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
-               printk(KERN_ERR "DRM not initialized, aborting suspend.\n");
+               DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
+               DRM_ERROR("DRM not initialized, aborting suspend.\n");
                return -ENODEV;
        }
 
@@ -115,6 +116,10 @@ static int i915_resume(struct drm_device *dev)
 
                drm_irq_install(dev);
        }
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Resume the modeset for every activated CRTC */
+               drm_helper_resume_force_mode(dev);
+       }
 
        return ret;
 }
index bb4c2d387b6c3eef6ab5b1a4f05fd9fc5f3393cf..d087528758856c78b5b8e6d6f4a1857dc5be20e4 100644 (file)
@@ -133,6 +133,22 @@ struct sdvo_device_mapping {
        u8 initialized;
 };
 
+struct drm_i915_error_state {
+       u32 eir;
+       u32 pgtbl_er;
+       u32 pipeastat;
+       u32 pipebstat;
+       u32 ipeir;
+       u32 ipehr;
+       u32 instdone;
+       u32 acthd;
+       u32 instpm;
+       u32 instps;
+       u32 instdone1;
+       u32 seqno;
+       struct timeval time;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
 
@@ -209,6 +225,11 @@ typedef struct drm_i915_private {
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
 
+       unsigned int fsb_freq, mem_freq;
+
+       spinlock_t error_lock;
+       struct drm_i915_error_state *first_error;
+
        /* Register state */
        u8 saveLBB;
        u32 saveDSPACNTR;
@@ -468,9 +489,6 @@ struct drm_i915_gem_object {
         */
        int fence_reg;
 
-       /** Boolean whether this object has a valid gtt offset. */
-       int gtt_bound;
-
        /** How many users have pinned this object in GTT space */
        int pin_count;
 
@@ -655,6 +673,7 @@ void i915_gem_free_object(struct drm_gem_object *obj);
 int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
 void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
+void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
 uint32_t i915_get_gem_seqno(struct drm_device *dev);
 int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
@@ -870,6 +889,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IGDNG(dev))
 #define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IGDNG(dev))
 #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
+/* dsparb controlled by hw only */
+#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
index 876b65cb7629f2e11c8e1f8f1bc76c05fcfc76bb..5bf420378b6d547a8146535c36830d84dd7bc087 100644 (file)
@@ -1252,6 +1252,31 @@ out_free_list:
        return ret;
 }
 
+/**
+ * i915_gem_release_mmap - remove physical page mappings
+ * @obj: obj in question
+ *
+ * Preserve the reservation of the mmaping with the DRM core code, but
+ * relinquish ownership of the pages back to the system.
+ *
+ * It is vital that we remove the page mapping if we have mapped a tiled
+ * object through the GTT and then lose the fence register due to
+ * resource pressure. Similarly if the object has been moved out of the
+ * aperture, than pages mapped into userspace must be revoked. Removing the
+ * mapping will then trigger a page fault on the next user access, allowing
+ * fixup by i915_gem_fault().
+ */
+void
+i915_gem_release_mmap(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       if (dev->dev_mapping)
+               unmap_mapping_range(dev->dev_mapping,
+                                   obj_priv->mmap_offset, obj->size, 1);
+}
+
 static void
 i915_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
@@ -1861,7 +1886,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
-       loff_t offset;
        int ret = 0;
 
 #if WATCH_BUF
@@ -1898,9 +1922,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        BUG_ON(obj_priv->active);
 
        /* blow away mappings if mapped through GTT */
-       offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT;
-       if (dev->dev_mapping)
-               unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1);
+       i915_gem_release_mmap(obj);
 
        if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
                i915_gem_clear_fence_reg(obj);
@@ -2222,7 +2244,6 @@ try_again:
        /* None available, try to steal one or wait for a user to finish */
        if (i == dev_priv->num_fence_regs) {
                uint32_t seqno = dev_priv->mm.next_gem_seqno;
-               loff_t offset;
 
                if (avail == 0)
                        return -ENOSPC;
@@ -2274,10 +2295,7 @@ try_again:
                 * Zap this virtual mapping so we can set up a fence again
                 * for this object next time we need it.
                 */
-               offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT;
-               if (dev->dev_mapping)
-                       unmap_mapping_range(dev->dev_mapping, offset,
-                                           reg->obj->size, 1);
+               i915_gem_release_mmap(reg->obj);
                old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
        }
 
index 28146e405e87404cf5177100ee2c467d8e5238e1..9a44bfcb81394c96a986b71e9b4da8ecb0ef7bee 100644 (file)
@@ -75,11 +75,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        case ACTIVE_LIST:
                seq_printf(m, "Active:\n");
                lock = &dev_priv->mm.active_list_lock;
-               spin_lock(lock);
                head = &dev_priv->mm.active_list;
                break;
        case INACTIVE_LIST:
-               seq_printf(m, "Inctive:\n");
+               seq_printf(m, "Inactive:\n");
                head = &dev_priv->mm.inactive_list;
                break;
        case FLUSHING_LIST:
@@ -91,6 +90,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
                return 0;
        }
 
+       if (lock)
+               spin_lock(lock);
        list_for_each_entry(obj_priv, head, list)
        {
                struct drm_gem_object *obj = obj_priv->obj;
@@ -104,7 +105,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
                if (obj->name)
                        seq_printf(m, " (name: %d)", obj->name);
                if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg);
+                       seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
+               if (obj_priv->gtt_space != NULL)
+                       seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
+
                seq_printf(m, "\n");
        }
 
@@ -323,6 +327,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_error_state(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->error_lock, flags);
+       if (!dev_priv->first_error) {
+               seq_printf(m, "no error state collected\n");
+               goto out;
+       }
+
+       error = dev_priv->first_error;
+
+       seq_printf(m, "EIR: 0x%08x\n", error->eir);
+       seq_printf(m, "  PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
+       seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir);
+       seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
+       seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
+       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
+       if (IS_I965G(dev)) {
+               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
+               seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
+       }
+
+out:
+       spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+
+       return 0;
+}
 
 static struct drm_info_list i915_gem_debugfs_list[] = {
        {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
@@ -336,6 +373,7 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
        {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
        {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
        {"i915_batchbuffers", i915_batchbuffer_info, 0},
+       {"i915_error_state", i915_error_state, 0},
 };
 #define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
 
index daeae62e1c28b889eb1a56b1e9d8e6d4963a3dd6..a2d527b22ec4f7ba837d9787f11585cf141cf844 100644 (file)
@@ -521,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                        goto err;
                }
 
+               /* If we've changed tiling, GTT-mappings of the object
+                * need to re-fault to ensure that the correct fence register
+                * setup is in place.
+                */
+               i915_gem_release_mmap(obj);
+
                obj_priv->tiling_mode = args->tiling_mode;
                obj_priv->stride = args->stride;
        }
index 228546f6eaa4f2ca876b70c1166677bb095d55ec..7ba23a69a0c0e39a983937a76d1178c6bea052ad 100644 (file)
@@ -26,6 +26,7 @@
  *
  */
 
+#include <linux/sysrq.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
  * we leave them always unmasked in IMR and then control enabling them through
  * PIPESTAT alone.
  */
-#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
-                                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |  \
-                                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT |                \
+                                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+                                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
+                                  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
 
 /** Interrupts that we mask and unmask at runtime. */
 #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
@@ -288,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
        return ret;
 }
 
+static void i915_capture_error_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->error_lock, flags);
+       if (dev_priv->first_error)
+               goto out;
+
+       error = kmalloc(sizeof(*error), GFP_ATOMIC);
+       if (!error) {
+               DRM_DEBUG("out ot memory, not capturing error state\n");
+               goto out;
+       }
+
+       error->eir = I915_READ(EIR);
+       error->pgtbl_er = I915_READ(PGTBL_ER);
+       error->pipeastat = I915_READ(PIPEASTAT);
+       error->pipebstat = I915_READ(PIPEBSTAT);
+       error->instpm = I915_READ(INSTPM);
+       if (!IS_I965G(dev)) {
+               error->ipeir = I915_READ(IPEIR);
+               error->ipehr = I915_READ(IPEHR);
+               error->instdone = I915_READ(INSTDONE);
+               error->acthd = I915_READ(ACTHD);
+       } else {
+               error->ipeir = I915_READ(IPEIR_I965);
+               error->ipehr = I915_READ(IPEHR_I965);
+               error->instdone = I915_READ(INSTDONE_I965);
+               error->instps = I915_READ(INSTPS);
+               error->instdone1 = I915_READ(INSTDONE1);
+               error->acthd = I915_READ(ACTHD_I965);
+       }
+
+       dev_priv->first_error = error;
+
+out:
+       spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -333,11 +376,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                 * Clear the PIPE(A|B)STAT regs before the IIR
                 */
                if (pipea_stats & 0x8000ffff) {
+                       if (pipea_stats &  PIPE_FIFO_UNDERRUN_STATUS)
+                               DRM_DEBUG("pipe a underrun\n");
                        I915_WRITE(PIPEASTAT, pipea_stats);
                        irq_received = 1;
                }
 
                if (pipeb_stats & 0x8000ffff) {
+                       if (pipeb_stats &  PIPE_FIFO_UNDERRUN_STATUS)
+                               DRM_DEBUG("pipe b underrun\n");
                        I915_WRITE(PIPEBSTAT, pipeb_stats);
                        irq_received = 1;
                }
@@ -362,6 +409,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
+               if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
+                       u32 eir = I915_READ(EIR);
+
+                       i915_capture_error_state(dev);
+
+                       printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
+                              eir);
+                       if (eir & I915_ERROR_PAGE_TABLE) {
+                               u32 pgtbl_err = I915_READ(PGTBL_ER);
+                               printk(KERN_ERR "page table error\n");
+                               printk(KERN_ERR "  PGTBL_ER: 0x%08x\n",
+                                      pgtbl_err);
+                               I915_WRITE(PGTBL_ER, pgtbl_err);
+                               (void)I915_READ(PGTBL_ER);
+                       }
+                       if (eir & I915_ERROR_MEMORY_REFRESH) {
+                               printk(KERN_ERR "memory refresh error\n");
+                               printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
+                                      pipea_stats);
+                               printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
+                                      pipeb_stats);
+                               /* pipestat has already been acked */
+                       }
+                       if (eir & I915_ERROR_INSTRUCTION) {
+                               printk(KERN_ERR "instruction error\n");
+                               printk(KERN_ERR "  INSTPM: 0x%08x\n",
+                                      I915_READ(INSTPM));
+                               if (!IS_I965G(dev)) {
+                                       u32 ipeir = I915_READ(IPEIR);
+
+                                       printk(KERN_ERR "  IPEIR: 0x%08x\n",
+                                              I915_READ(IPEIR));
+                                       printk(KERN_ERR "  IPEHR: 0x%08x\n",
+                                                  I915_READ(IPEHR));
+                                       printk(KERN_ERR "  INSTDONE: 0x%08x\n",
+                                                  I915_READ(INSTDONE));
+                                       printk(KERN_ERR "  ACTHD: 0x%08x\n",
+                                                  I915_READ(ACTHD));
+                                       I915_WRITE(IPEIR, ipeir);
+                                       (void)I915_READ(IPEIR);
+                               } else {
+                                       u32 ipeir = I915_READ(IPEIR_I965);
+
+                                       printk(KERN_ERR "  IPEIR: 0x%08x\n",
+                                              I915_READ(IPEIR_I965));
+                                       printk(KERN_ERR "  IPEHR: 0x%08x\n",
+                                              I915_READ(IPEHR_I965));
+                                       printk(KERN_ERR "  INSTDONE: 0x%08x\n",
+                                              I915_READ(INSTDONE_I965));
+                                       printk(KERN_ERR "  INSTPS: 0x%08x\n",
+                                              I915_READ(INSTPS));
+                                       printk(KERN_ERR "  INSTDONE1: 0x%08x\n",
+                                              I915_READ(INSTDONE1));
+                                       printk(KERN_ERR "  ACTHD: 0x%08x\n",
+                                              I915_READ(ACTHD_I965));
+                                       I915_WRITE(IPEIR_I965, ipeir);
+                                       (void)I915_READ(IPEIR_I965);
+                               }
+                       }
+
+                       I915_WRITE(EIR, eir);
+                       (void)I915_READ(EIR);
+                       eir = I915_READ(EIR);
+                       if (eir) {
+                               /*
+                                * some errors might have become stuck,
+                                * mask them.
+                                */
+                               DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
+                               I915_WRITE(EMR, I915_READ(EMR) | eir);
+                               I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+                       }
+               }
+
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
@@ -732,6 +853,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
+       u32 error_mask;
 
        DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
@@ -768,6 +890,21 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
                i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
        }
 
+       /*
+        * Enable some error detection, note the instruction error mask
+        * bit is reserved, so we leave it masked.
+        */
+       if (IS_G4X(dev)) {
+               error_mask = ~(GM45_ERROR_PAGE_TABLE |
+                              GM45_ERROR_MEM_PRIV |
+                              GM45_ERROR_CP_PRIV |
+                              I915_ERROR_MEMORY_REFRESH);
+       } else {
+               error_mask = ~(I915_ERROR_PAGE_TABLE |
+                              I915_ERROR_MEMORY_REFRESH);
+       }
+       I915_WRITE(EMR, error_mask);
+
        /* Disable pipe interrupt enables, clear pending pipe status */
        I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
        I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
index 88bf7521405f51a672f0c47eb0d2c3a48f235cbb..6c08584840944d6e711386ba8b4352b8c9dcdce3 100644 (file)
 /*
  * Instruction and interrupt control regs
  */
+#define PGTBL_ER       0x02024
 #define PRB0_TAIL      0x02030
 #define PRB0_HEAD      0x02034
 #define PRB0_START     0x02038
 #define PRB1_HEAD      0x02044 /* 915+ only */
 #define PRB1_START     0x02048 /* 915+ only */
 #define PRB1_CTL       0x0204c /* 915+ only */
+#define IPEIR_I965     0x02064
+#define IPEHR_I965     0x02068
+#define INSTDONE_I965  0x0206c
+#define INSTPS         0x02070 /* 965+ only */
+#define INSTDONE1      0x0207c /* 965+ only */
 #define ACTHD_I965     0x02074
 #define HWS_PGA                0x02080
 #define HWS_ADDRESS_MASK       0xfffff000
 #define HWS_START_ADDRESS_SHIFT        4
 #define IPEIR          0x02088
+#define IPEHR          0x0208c
+#define INSTDONE       0x02090
 #define NOPID          0x02094
 #define HWSTAM         0x02098
 #define SCPD0          0x0209c /* 915+ only */
 #define EIR            0x020b0
 #define EMR            0x020b4
 #define ESR            0x020b8
+#define   GM45_ERROR_PAGE_TABLE                                (1<<5)
+#define   GM45_ERROR_MEM_PRIV                          (1<<4)
+#define   I915_ERROR_PAGE_TABLE                                (1<<4)
+#define   GM45_ERROR_CP_PRIV                           (1<<3)
+#define   I915_ERROR_MEMORY_REFRESH                    (1<<1)
+#define   I915_ERROR_INSTRUCTION                       (1<<0)
 #define INSTPM         0x020c0
 #define ACTHD          0x020c8
 #define FW_BLC         0x020d8
+#define FW_BLC2                0x020dc
 #define FW_BLC_SELF    0x020e0 /* 915+ only */
+#define   FW_BLC_SELF_EN (1<<15)
+#define MM_BURST_LENGTH     0x00700000
+#define MM_FIFO_WATERMARK   0x0001F000
+#define LM_BURST_LENGTH     0x00000700
+#define LM_FIFO_WATERMARK   0x0000001F
 #define MI_ARB_STATE   0x020e4 /* 915+ only */
 #define CACHE_MODE_0   0x02120 /* 915+ only */
 #define   CM0_MASK_SHIFT          16
 
 /* Clocking configuration register */
 #define CLKCFG                 0x10c00
-#define CLKCFG_FSB_400                                 (0 << 0)        /* hrawclk 100 */
+#define CLKCFG_FSB_400                                 (5 << 0)        /* hrawclk 100 */
 #define CLKCFG_FSB_533                                 (1 << 0)        /* hrawclk 133 */
 #define CLKCFG_FSB_667                                 (3 << 0)        /* hrawclk 166 */
 #define CLKCFG_FSB_800                                 (2 << 0)        /* hrawclk 200 */
 #define CLKCFG_FSB_1067                                        (6 << 0)        /* hrawclk 266 */
 #define CLKCFG_FSB_1333                                        (7 << 0)        /* hrawclk 333 */
-/* this is a guess, could be 5 as well */
+/* Note, below two are guess */
 #define CLKCFG_FSB_1600                                        (4 << 0)        /* hrawclk 400 */
-#define CLKCFG_FSB_1600_ALT                            (5 << 0)        /* hrawclk 400 */
+#define CLKCFG_FSB_1600_ALT                            (0 << 0)        /* hrawclk 400 */
 #define CLKCFG_FSB_MASK                                        (7 << 0)
+#define CLKCFG_MEM_533                                 (1 << 4)
+#define CLKCFG_MEM_667                                 (2 << 4)
+#define CLKCFG_MEM_800                                 (3 << 4)
+#define CLKCFG_MEM_MASK                                        (7 << 4)
+
 /** GM965 GM45 render standby register */
 #define MCHBAR_RENDER_STANDBY  0x111B8
 
 #define   DSPARB_CSTART_SHIFT  7
 #define   DSPARB_BSTART_MASK   (0x7f)
 #define   DSPARB_BSTART_SHIFT  0
+#define   DSPARB_BEND_SHIFT    9 /* on 855 */
+#define   DSPARB_AEND_SHIFT    0
+
+#define DSPFW1                 0x70034
+#define DSPFW2                 0x70038
+#define DSPFW3                 0x7003c
+#define   IGD_SELF_REFRESH_EN  (1<<30)
+
+/* FIFO watermark sizes etc */
+#define I915_FIFO_LINE_SIZE    64
+#define I830_FIFO_LINE_SIZE    32
+#define I945_FIFO_SIZE         127 /* 945 & 965 */
+#define I915_FIFO_SIZE         95
+#define I855GM_FIFO_SIZE       255
+#define I830_FIFO_SIZE         95
+#define I915_MAX_WM            0x3f
+
+#define IGD_DISPLAY_FIFO       512 /* in 64byte unit */
+#define IGD_FIFO_LINE_SIZE     64
+#define IGD_MAX_WM             0x1ff
+#define IGD_DFT_WM             0x3f
+#define IGD_DFT_HPLLOFF_WM     0
+#define IGD_GUARD_WM           10
+#define IGD_CURSOR_FIFO                64
+#define IGD_CURSOR_MAX_WM      0x3f
+#define IGD_CURSOR_DFT_WM      0
+#define IGD_CURSOR_GUARD_WM    5
+
 /*
  * The two pipe frame counter registers are not synchronized, so
  * reading a stable value is somewhat tricky. The following code
index 8d8e083d14ab22acaea6d3d246655bbc7d76f13a..9e1d16e5c3ead86f0e805f9d72a95eb7be8e293e 100644 (file)
@@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev)
        I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
 }
 
-int i915_save_state(struct drm_device *dev)
+static void i915_save_modeset_reg(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
-
-       /* Render Standby */
-       if (IS_I965G(dev) && IS_MOBILE(dev))
-               dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
-
-       /* Hardware status page */
-       dev_priv->saveHWS = I915_READ(HWS_PGA);
-
-       /* Display arbitration control */
-       dev_priv->saveDSPARB = I915_READ(DSPARB);
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
        /* Pipe & plane A info */
        dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
        dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
@@ -294,7 +283,122 @@ int i915_save_state(struct drm_device *dev)
        }
        i915_save_palette(dev, PIPE_B);
        dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+       return;
+}
+static void i915_restore_modeset_reg(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
+
+       /* Pipe & plane A info */
+       /* Prime the clock */
+       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPA0, dev_priv->saveFPA0);
+       I915_WRITE(FPA1, dev_priv->saveFPA1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+
+       /* Restore plane info */
+       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+       I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
+       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+       }
+
+       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+       i915_restore_palette(dev, PIPE_A);
+       /* Enable the plane */
+       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+       I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
+
+       /* Pipe & plane B info */
+       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPB0, dev_priv->saveFPB0);
+       I915_WRITE(FPB1, dev_priv->saveFPB1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+
+       /* Restore plane info */
+       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+       I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
+       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+       }
+
+       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+       i915_restore_palette(dev, PIPE_B);
+       /* Enable the plane */
+       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+       I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
 
+       return;
+}
+int i915_save_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+
+       /* Render Standby */
+       if (IS_I965G(dev) && IS_MOBILE(dev))
+               dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
+
+       /* Hardware status page */
+       dev_priv->saveHWS = I915_READ(HWS_PGA);
+
+       /* Display arbitration control */
+       dev_priv->saveDSPARB = I915_READ(DSPARB);
+
+       /* This is only meaningful in non-KMS mode */
+       /* Don't save them in KMS mode */
+       i915_save_modeset_reg(dev);
        /* Cursor state */
        dev_priv->saveCURACNTR = I915_READ(CURACNTR);
        dev_priv->saveCURAPOS = I915_READ(CURAPOS);
@@ -430,92 +534,9 @@ int i915_restore_state(struct drm_device *dev)
                I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
                I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
        }
-       
-       /* Pipe & plane A info */
-       /* Prime the clock */
-       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
-                          ~DPLL_VCO_ENABLE);
-               DRM_UDELAY(150);
-       }
-       I915_WRITE(FPA0, dev_priv->saveFPA0);
-       I915_WRITE(FPA1, dev_priv->saveFPA1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
-       DRM_UDELAY(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
-       DRM_UDELAY(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
-       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
-       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
-       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
-       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
-       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
-       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
-
-       /* Restore plane info */
-       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
-       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
-       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
-       I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
-       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
-               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
-       }
-
-       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
-
-       i915_restore_palette(dev, PIPE_A);
-       /* Enable the plane */
-       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
-       I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
-
-       /* Pipe & plane B info */
-       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
-                          ~DPLL_VCO_ENABLE);
-               DRM_UDELAY(150);
-       }
-       I915_WRITE(FPB0, dev_priv->saveFPB0);
-       I915_WRITE(FPB1, dev_priv->saveFPB1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
-       DRM_UDELAY(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
-       DRM_UDELAY(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
-       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
-       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
-       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
-       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
-       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
-       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
-
-       /* Restore plane info */
-       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
-       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
-       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
-       I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
-       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
-               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
-       }
-
-       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
-
-       i915_restore_palette(dev, PIPE_B);
-       /* Enable the plane */
-       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
-       I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
-
+       /* This is only meaningful in non-KMS mode */
+       /* Don't restore them in KMS mode */
+       i915_restore_modeset_reg(dev);
        /* Cursor state */
        I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
        I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
index 716409a57244b710684deb66e59f11ed3b0dc81e..7cc447191028d70f11b6ea5c0082492d5d0247df 100644 (file)
@@ -97,6 +97,7 @@ static void
 parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                            struct bdb_header *bdb)
 {
+       struct drm_device *dev = dev_priv->dev;
        struct bdb_lvds_options *lvds_options;
        struct bdb_lvds_lfp_data *lvds_lfp_data;
        struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
@@ -132,7 +133,14 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        entry = (struct bdb_lvds_lfp_data_entry *)
                ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
                                                   lvds_options->panel_type));
-       dvo_timing = &entry->dvo_timing;
+
+       /* On IGDNG mobile, LVDS data block removes panel fitting registers.
+          So dec 2 dword from dvo_timing offset */
+       if (IS_IGDNG(dev))
+               dvo_timing = (struct lvds_dvo_timing *)
+                                       ((u8 *)&entry->dvo_timing - 8);
+       else
+               dvo_timing = &entry->dvo_timing;
 
        panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
 
@@ -195,10 +203,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
                dev_priv->lvds_use_ssc = general->enable_ssc;
 
                if (dev_priv->lvds_use_ssc) {
-                 if (IS_I855(dev_priv->dev))
-                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
-                 else
-                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
+                       if (IS_I85X(dev_priv->dev))
+                               dev_priv->lvds_ssc_freq =
+                                       general->ssc_freq ? 66 : 48;
+                       else
+                               dev_priv->lvds_ssc_freq =
+                                       general->ssc_freq ? 100 : 96;
                }
        }
 }
index 6de97fc66029ed2f28707649f65dfd19ea87d042..d6a1a6e5539a58da94b57ad67e3db54486963a5a 100644 (file)
@@ -46,7 +46,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 
        temp = I915_READ(reg);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
-       temp |= ADPA_DAC_ENABLE;
+       temp &= ~ADPA_DAC_ENABLE;
 
        switch(mode) {
        case DRM_MODE_DPMS_ON:
@@ -428,8 +428,34 @@ static void intel_crt_destroy(struct drm_connector *connector)
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
+       int ret;
        struct intel_output *intel_output = to_intel_output(connector);
-       return intel_ddc_get_modes(intel_output);
+       struct i2c_adapter *ddcbus;
+       struct drm_device *dev = connector->dev;
+
+
+       ret = intel_ddc_get_modes(intel_output);
+       if (ret || !IS_G4X(dev))
+               goto end;
+
+       ddcbus = intel_output->ddc_bus;
+       /* Try to probe digital port for output in DVI-I -> VGA mode. */
+       intel_output->ddc_bus =
+               intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
+
+       if (!intel_output->ddc_bus) {
+               intel_output->ddc_bus = ddcbus;
+               dev_printk(KERN_ERR, &connector->dev->pdev->dev,
+                          "DDC bus registration failed for CRTDDC_D.\n");
+               goto end;
+       }
+       /* Try to get modes by GPIOD port */
+       ret = intel_ddc_get_modes(intel_output);
+       intel_i2c_destroy(ddcbus);
+
+end:
+       return ret;
+
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
index 73e7b9cecac82ae51e40939bd7cd77b0a975eaea..508838ee31e023f2ac1038236299b7ea7eb4e38b 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/i2c.h>
+#include <linux/kernel.h>
 #include "drmP.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
@@ -34,6 +35,7 @@
 #include "drm_crtc_helper.h"
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
+static void intel_update_watermarks(struct drm_device *dev);
 
 typedef struct {
     /* given values */
@@ -814,24 +816,21 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
 {
     intel_clock_t clock;
     if (target < 200000) {
-       clock.dot = 161670;
-       clock.p = 20;
        clock.p1 = 2;
        clock.p2 = 10;
-       clock.n = 0x01;
-       clock.m = 97;
-       clock.m1 = 0x10;
-       clock.m2 = 0x05;
+       clock.n = 2;
+       clock.m1 = 23;
+       clock.m2 = 8;
     } else {
-       clock.dot = 270000;
-       clock.p = 10;
        clock.p1 = 1;
        clock.p2 = 10;
-       clock.n = 0x02;
-       clock.m = 108;
-       clock.m1 = 0x12;
-       clock.m2 = 0x06;
+       clock.n = 1;
+       clock.m1 = 14;
+       clock.m2 = 2;
     }
+    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+    clock.p = (clock.p1 * clock.p2);
+    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
     memcpy(best_clock, &clock, sizeof(intel_clock_t));
     return true;
 }
@@ -1005,7 +1004,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
        int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
        int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
        int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
@@ -1335,8 +1334,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 
                /* Give the overlay scaler a chance to enable if it's on this pipe */
                //intel_crtc_dpms_video(crtc, true); TODO
+               intel_update_watermarks(dev);
        break;
        case DRM_MODE_DPMS_OFF:
+               intel_update_watermarks(dev);
                /* Give the overlay scaler a chance to disable if it's on this pipe */
                //intel_crtc_dpms_video(crtc, FALSE); TODO
 
@@ -1515,7 +1516,6 @@ static int intel_get_core_clock_speed(struct drm_device *dev)
        return 0; /* Silence gcc warning */
 }
 
-
 /**
  * Return the pipe currently connected to the panel fitter,
  * or -1 if the panel fitter is not present or not in use
@@ -1574,7 +1574,7 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
 
        temp = (u64) DATA_N * pixel_clock;
        temp = div_u64(temp, link_clock);
-       m_n->gmch_m = (temp * bytes_per_pixel) / nlanes;
+       m_n->gmch_m = div_u64(temp * bytes_per_pixel, nlanes);
        m_n->gmch_n = DATA_N;
        fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
 
@@ -1585,6 +1585,420 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
 }
 
 
+struct intel_watermark_params {
+       unsigned long fifo_size;
+       unsigned long max_wm;
+       unsigned long default_wm;
+       unsigned long guard_size;
+       unsigned long cacheline_size;
+};
+
+/* IGD has different values for various configs */
+static struct intel_watermark_params igd_display_wm = {
+       IGD_DISPLAY_FIFO,
+       IGD_MAX_WM,
+       IGD_DFT_WM,
+       IGD_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params igd_display_hplloff_wm = {
+       IGD_DISPLAY_FIFO,
+       IGD_MAX_WM,
+       IGD_DFT_HPLLOFF_WM,
+       IGD_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params igd_cursor_wm = {
+       IGD_CURSOR_FIFO,
+       IGD_CURSOR_MAX_WM,
+       IGD_CURSOR_DFT_WM,
+       IGD_CURSOR_GUARD_WM,
+       IGD_FIFO_LINE_SIZE,
+};
+static struct intel_watermark_params igd_cursor_hplloff_wm = {
+       IGD_CURSOR_FIFO,
+       IGD_CURSOR_MAX_WM,
+       IGD_CURSOR_DFT_WM,
+       IGD_CURSOR_GUARD_WM,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i945_wm_info = {
+       I915_FIFO_LINE_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       IGD_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i915_wm_info = {
+       I945_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I915_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i855_wm_info = {
+       I855GM_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I830_FIFO_LINE_SIZE
+};
+static struct intel_watermark_params i830_wm_info = {
+       I830_FIFO_SIZE,
+       I915_MAX_WM,
+       1,
+       0,
+       I830_FIFO_LINE_SIZE
+};
+
+static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
+                                       struct intel_watermark_params *wm,
+                                       int pixel_size,
+                                       unsigned long latency_ns)
+{
+       unsigned long bytes_required, wm_size;
+
+       bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
+       bytes_required /= wm->cacheline_size;
+       wm_size = wm->fifo_size - bytes_required - wm->guard_size;
+
+       if (wm_size > wm->max_wm)
+               wm_size = wm->max_wm;
+       if (wm_size == 0)
+               wm_size = wm->default_wm;
+       return wm_size;
+}
+
+struct cxsr_latency {
+       int is_desktop;
+       unsigned long fsb_freq;
+       unsigned long mem_freq;
+       unsigned long display_sr;
+       unsigned long display_hpll_disable;
+       unsigned long cursor_sr;
+       unsigned long cursor_hpll_disable;
+};
+
+static struct cxsr_latency cxsr_latency_table[] = {
+       {1, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
+       {1, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
+       {1, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
+
+       {1, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
+       {1, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
+       {1, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
+
+       {1, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
+       {1, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
+       {1, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
+
+       {0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
+       {0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
+       {0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
+
+       {0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
+       {0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
+       {0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
+
+       {0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
+       {0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
+       {0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
+};
+
+static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
+                                                  int mem)
+{
+       int i;
+       struct cxsr_latency *latency;
+
+       if (fsb == 0 || mem == 0)
+               return NULL;
+
+       for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
+               latency = &cxsr_latency_table[i];
+               if (is_desktop == latency->is_desktop &&
+                       fsb == latency->fsb_freq && mem == latency->mem_freq)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(cxsr_latency_table)) {
+               DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
+               return NULL;
+       }
+       return latency;
+}
+
+static void igd_disable_cxsr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+
+       /* deactivate cxsr */
+       reg = I915_READ(DSPFW3);
+       reg &= ~(IGD_SELF_REFRESH_EN);
+       I915_WRITE(DSPFW3, reg);
+       DRM_INFO("Big FIFO is disabled\n");
+}
+
+static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
+                           int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+       unsigned long wm;
+       struct cxsr_latency *latency;
+
+       latency = intel_get_cxsr_latency(IS_IGDG(dev), dev_priv->fsb_freq,
+               dev_priv->mem_freq);
+       if (!latency) {
+               DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
+               igd_disable_cxsr(dev);
+               return;
+       }
+
+       /* Display SR */
+       wm = intel_calculate_wm(clock, &igd_display_wm, pixel_size,
+                               latency->display_sr);
+       reg = I915_READ(DSPFW1);
+       reg &= 0x7fffff;
+       reg |= wm << 23;
+       I915_WRITE(DSPFW1, reg);
+       DRM_DEBUG("DSPFW1 register is %x\n", reg);
+
+       /* cursor SR */
+       wm = intel_calculate_wm(clock, &igd_cursor_wm, pixel_size,
+                               latency->cursor_sr);
+       reg = I915_READ(DSPFW3);
+       reg &= ~(0x3f << 24);
+       reg |= (wm & 0x3f) << 24;
+       I915_WRITE(DSPFW3, reg);
+
+       /* Display HPLL off SR */
+       wm = intel_calculate_wm(clock, &igd_display_hplloff_wm,
+               latency->display_hpll_disable, I915_FIFO_LINE_SIZE);
+       reg = I915_READ(DSPFW3);
+       reg &= 0xfffffe00;
+       reg |= wm & 0x1ff;
+       I915_WRITE(DSPFW3, reg);
+
+       /* cursor HPLL off SR */
+       wm = intel_calculate_wm(clock, &igd_cursor_hplloff_wm, pixel_size,
+                               latency->cursor_hpll_disable);
+       reg = I915_READ(DSPFW3);
+       reg &= ~(0x3f << 16);
+       reg |= (wm & 0x3f) << 16;
+       I915_WRITE(DSPFW3, reg);
+       DRM_DEBUG("DSPFW3 register is %x\n", reg);
+
+       /* activate cxsr */
+       reg = I915_READ(DSPFW3);
+       reg |= IGD_SELF_REFRESH_EN;
+       I915_WRITE(DSPFW3, reg);
+
+       DRM_INFO("Big FIFO is enabled\n");
+
+       return;
+}
+
+const static int latency_ns = 5000; /* default for non-igd platforms */
+
+
+static void i965_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR 8\n");
+
+       /* 965 has limitations... */
+       I915_WRITE(DSPFW1, (8 << 16) | (8 << 8) | (8 << 0));
+       I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+}
+
+static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
+                          int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
+       uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK;
+       int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1;
+       uint32_t dsparb = I915_READ(DSPARB);
+       int planea_entries, planeb_entries;
+       struct intel_watermark_params *wm_params;
+       unsigned long line_time_us;
+       int sr_clock, sr_entries = 0;
+
+       if (IS_I965GM(dev) || IS_I945GM(dev))
+               wm_params = &i945_wm_info;
+       else if (IS_I9XX(dev))
+               wm_params = &i915_wm_info;
+       else
+               wm_params = &i855_wm_info;
+
+       planea_entries = intel_calculate_wm(planea_clock, wm_params,
+                                           pixel_size, latency_ns);
+       planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
+                                           pixel_size, latency_ns);
+
+       DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries,
+                 planeb_entries);
+
+       if (IS_I9XX(dev)) {
+               asize = dsparb & 0x7f;
+               bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f;
+       } else {
+               asize = dsparb & 0x1ff;
+               bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
+       }
+       DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
+
+       /* Two extra entries for padding */
+       awm = asize - (planea_entries + 2);
+       bwm = bsize - (planeb_entries + 2);
+
+       /* Sanity check against potentially bad FIFO allocations */
+       if (awm <= 0) {
+               /* pipe is on but has too few FIFO entries */
+               if (planea_entries != 0)
+                       DRM_DEBUG("plane A needs more FIFO entries\n");
+               awm = 1;
+       }
+       if (bwm <= 0) {
+               if (planeb_entries != 0)
+                       DRM_DEBUG("plane B needs more FIFO entries\n");
+               bwm = 1;
+       }
+
+       /*
+        * Overlay gets an aggressive default since video jitter is bad.
+        */
+       cwm = 2;
+
+       /* Calc sr entries for one pipe configs */
+       if (!planea_clock || !planeb_clock) {
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
+               line_time_us = (sr_hdisplay * 1000) / sr_clock;
+               sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size *
+                             sr_hdisplay) / 1000;
+               sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1);
+               if (sr_entries < wm_params->fifo_size)
+                       srwm = wm_params->fifo_size - sr_entries;
+       }
+
+       DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
+                 awm, bwm, cwm, srwm);
+
+       fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f);
+       fwater_hi = fwater_hi | (cwm & 0x1f);
+
+       I915_WRITE(FW_BLC, fwater_lo);
+       I915_WRITE(FW_BLC2, fwater_hi);
+       if (IS_I9XX(dev))
+               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
+}
+
+static void i830_update_wm(struct drm_device *dev, int planea_clock,
+                          int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dsparb = I915_READ(DSPARB);
+       uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
+       unsigned int asize, awm;
+       int planea_entries;
+
+       planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
+                                           pixel_size, latency_ns);
+
+       asize = dsparb & 0x7f;
+
+       awm = asize - planea_entries;
+
+       fwater_lo = fwater_lo | awm;
+
+       I915_WRITE(FW_BLC, fwater_lo);
+}
+
+/**
+ * intel_update_watermarks - update FIFO watermark values based on current modes
+ *
+ * Calculate watermark values for the various WM regs based on current mode
+ * and plane configuration.
+ *
+ * There are several cases to deal with here:
+ *   - normal (i.e. non-self-refresh)
+ *   - self-refresh (SR) mode
+ *   - lines are large relative to FIFO size (buffer can hold up to 2)
+ *   - lines are small relative to FIFO size (buffer can hold more than 2
+ *     lines), so need to account for TLB latency
+ *
+ *   The normal calculation is:
+ *     watermark = dotclock * bytes per pixel * latency
+ *   where latency is platform & configuration dependent (we assume pessimal
+ *   values here).
+ *
+ *   The SR calculation is:
+ *     watermark = (trunc(latency/line time)+1) * surface width *
+ *       bytes per pixel
+ *   where
+ *     line time = htotal / dotclock
+ *   and latency is assumed to be high, as above.
+ *
+ * The final value programmed to the register should always be rounded up,
+ * and include an extra 2 entries to account for clock crossings.
+ *
+ * We don't use the sprite, so we can ignore that.  And on Crestline we have
+ * to set the non-SR watermarks to 8.
+  */
+static void intel_update_watermarks(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       int sr_hdisplay = 0;
+       unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
+       int enabled = 0, pixel_size = 0;
+
+       if (DSPARB_HWCONTROL(dev))
+               return;
+
+       /* Get the clock config from both planes */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+               if (crtc->enabled) {
+                       enabled++;
+                       if (intel_crtc->plane == 0) {
+                               DRM_DEBUG("plane A (pipe %d) clock: %d\n",
+                                         intel_crtc->pipe, crtc->mode.clock);
+                               planea_clock = crtc->mode.clock;
+                       } else {
+                               DRM_DEBUG("plane B (pipe %d) clock: %d\n",
+                                         intel_crtc->pipe, crtc->mode.clock);
+                               planeb_clock = crtc->mode.clock;
+                       }
+                       sr_hdisplay = crtc->mode.hdisplay;
+                       sr_clock = crtc->mode.clock;
+                       if (crtc->fb)
+                               pixel_size = crtc->fb->bits_per_pixel / 8;
+                       else
+                               pixel_size = 4; /* by default */
+               }
+       }
+
+       if (enabled <= 0)
+               return;
+
+       /* Single pipe configs can enable self refresh */
+       if (enabled == 1 && IS_IGD(dev))
+               igd_enable_cxsr(dev, sr_clock, pixel_size);
+       else if (IS_IGD(dev))
+               igd_disable_cxsr(dev);
+
+       if (IS_I965G(dev))
+               i965_update_wm(dev);
+       else if (IS_I9XX(dev) || IS_MOBILE(dev))
+               i9xx_update_wm(dev, planea_clock, planeb_clock, sr_hdisplay,
+                              pixel_size);
+       else
+               i830_update_wm(dev, planea_clock, pixel_size);
+}
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode,
@@ -1951,6 +2365,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
+
+       intel_update_watermarks(dev);
+
        drm_vblank_post_modeset(dev, pipe);
 
        return ret;
@@ -2439,6 +2856,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
        intel_crtc->pipe = pipe;
+       intel_crtc->plane = pipe;
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
                intel_crtc->lut_g[i] = i;
index 8f8d37d5663a0cacb53f2b776abbae0b2e2b42f9..6770ae88370d6de67c437e918f559c20ddf70e48 100644 (file)
@@ -246,7 +246,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
        }
 
        if ((status & DP_AUX_CH_CTL_DONE) == 0) {
-               printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status);
+               DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
                return -EBUSY;
        }
 
@@ -254,11 +254,14 @@ intel_dp_aux_ch(struct intel_output *intel_output,
         * Timeouts occur when the sink is not connected
         */
        if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
-               printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status);
+               DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
                return -EIO;
        }
+
+       /* Timeouts occur when the device isn't connected, so they're
+        * "normal" -- don't fill the kernel log with these */
        if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
-               printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status);
+               DRM_DEBUG("dp_aux_ch timeout status 0x%08x\n", status);
                return -ETIMEDOUT;
        }
 
@@ -411,7 +414,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                                dp_priv->link_bw = bws[clock];
                                dp_priv->lane_count = lane_count;
                                adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
-                               printk(KERN_ERR "link bw %02x lane count %d clock %d\n",
+                               DRM_DEBUG("Display port link bw %02x lane count %d clock %d\n",
                                       dp_priv->link_bw, dp_priv->lane_count,
                                       adjusted_mode->clock);
                                return true;
index 4e60f14b1a6db12d42155f7f6b0edb30c9cbfdb8..a63b6f57d2d4eccf9b22f9cb2bd4c0d1cb229d44 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/i2c.h>
 #include "intel_dp.h"
+#include "drmP.h"
 
 /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
 
@@ -84,7 +85,7 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
                                           msg, msg_bytes,
                                           reply, reply_bytes);
                if (ret < 0) {
-                       printk(KERN_ERR "aux_ch failed %d\n", ret);
+                       DRM_DEBUG("aux_ch failed %d\n", ret);
                        return ret;
                }
                switch (reply[0] & AUX_I2C_REPLY_MASK) {
@@ -94,14 +95,14 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
                        }
                        return reply_bytes - 1;
                case AUX_I2C_REPLY_NACK:
-                       printk(KERN_ERR "aux_ch nack\n");
+                       DRM_DEBUG("aux_ch nack\n");
                        return -EREMOTEIO;
                case AUX_I2C_REPLY_DEFER:
-                       printk(KERN_ERR "aux_ch defer\n");
+                       DRM_DEBUG("aux_ch defer\n");
                        udelay(100);
                        break;
                default:
-                       printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]);
+                       DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
                        return -EREMOTEIO;
                }
        }
@@ -223,7 +224,7 @@ i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
        if (ret >= 0)
                ret = num;
        i2c_algo_dp_aux_stop(adapter, reading);
-       printk(KERN_ERR "dp_aux_xfer return %d\n", ret);
+       DRM_DEBUG("dp_aux_xfer return %d\n", ret);
        return ret;
 }
 
index 1af7d68e380756f3f785551cb9c8a4c38da8604a..1d30802e773e383492c03aeabb99e6a3ddd623f2 100644 (file)
@@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        size = ALIGN(size, PAGE_SIZE);
        fbo = drm_gem_object_alloc(dev, size);
        if (!fbo) {
-               printk(KERN_ERR "failed to allocate framebuffer\n");
+               DRM_ERROR("failed to allocate framebuffer\n");
                ret = -ENOMEM;
                goto out;
        }
@@ -610,8 +610,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        par->dev = dev;
 
        /* To allow resizeing without swapping buffers */
-       printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
-              intel_fb->base.height, obj_priv->gtt_offset, fbo);
+       DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
+                 intel_fb->base.height, obj_priv->gtt_offset, fbo);
 
        mutex_unlock(&dev->struct_mutex);
        return 0;
@@ -698,13 +698,13 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
        } else
                intelfb_set_par(info);
 
-       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
               info->fix.id);
 
        /* Switch back to kernel console on panic */
        kernelfb_mode = *modeset;
        atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       printk(KERN_INFO "registered panic notifier\n");
+       DRM_DEBUG("registered panic notifier\n");
 
        return 0;
 }
@@ -852,13 +852,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
        } else
                intelfb_set_par(info);
 
-       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+       DRM_INFO("fb%d: %s frame buffer device\n", info->node,
               info->fix.id);
 
        /* Switch back to kernel console on panic */
        kernelfb_mode = *modeset;
        atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-       printk(KERN_INFO "registered panic notifier\n");
+       DRM_DEBUG("registered panic notifier\n");
 
        return 0;
 }
@@ -872,8 +872,8 @@ void intelfb_restore(void)
 {
        int ret;
        if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
-               printk(KERN_ERR "Failed to restore crtc configuration: %d\n",
-                      ret);
+               DRM_ERROR("Failed to restore crtc configuration: %d\n",
+                         ret);
        }
 }
 
index 9564ca44a977e71ab02d9a77e4df2f6dc52dc82d..9ab38efffecfeab426e48c45bbc3a7ee77bf96f4 100644 (file)
@@ -36,6 +36,7 @@
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include <linux/acpi.h>
 
 #define I915_LVDS "i915_lvds"
 
@@ -252,14 +253,14 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 
        /* Should never happen!! */
        if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
-               printk(KERN_ERR "Can't support LVDS on pipe A\n");
+               DRM_ERROR("Can't support LVDS on pipe A\n");
                return false;
        }
 
        /* Should never happen!! */
        list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
                if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
-                       printk(KERN_ERR "Can't enable LVDS and another "
+                       DRM_ERROR("Can't enable LVDS and another "
                               "encoder on the same pipe\n");
                        return false;
                }
@@ -788,6 +789,65 @@ static const struct dmi_system_id intel_no_lvds[] = {
        { }     /* terminating entry */
 };
 
+#ifdef CONFIG_ACPI
+/*
+ * check_lid_device -- check whether @handle is an ACPI LID device.
+ * @handle: ACPI device handle
+ * @level : depth in the ACPI namespace tree
+ * @context: the number of LID device when we find the device
+ * @rv: a return value to fill if desired (Not use)
+ */
+static acpi_status
+check_lid_device(acpi_handle handle, u32 level, void *context,
+                       void **return_value)
+{
+       struct acpi_device *acpi_dev;
+       int *lid_present = context;
+
+       acpi_dev = NULL;
+       /* Get the acpi device for device handle */
+       if (acpi_bus_get_device(handle, &acpi_dev) || !acpi_dev) {
+               /* If there is no ACPI device for handle, return */
+               return AE_OK;
+       }
+
+       if (!strncmp(acpi_device_hid(acpi_dev), "PNP0C0D", 7))
+               *lid_present = 1;
+
+       return AE_OK;
+}
+
+/**
+ * check whether there exists the ACPI LID device by enumerating the ACPI
+ * device tree.
+ */
+static int intel_lid_present(void)
+{
+       int lid_present = 0;
+
+       if (acpi_disabled) {
+               /* If ACPI is disabled, there is no ACPI device tree to
+                * check, so assume the LID device would have been present.
+                */
+               return 1;
+       }
+
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                               ACPI_UINT32_MAX,
+                               check_lid_device, &lid_present, NULL);
+
+       return lid_present;
+}
+#else
+static int intel_lid_present(void)
+{
+       /* In the absence of ACPI built in, assume that the LID device would
+        * have been present.
+        */
+       return 1;
+}
+#endif
+
 /**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -811,6 +871,16 @@ void intel_lvds_init(struct drm_device *dev)
        if (dmi_check_system(intel_no_lvds))
                return;
 
+       /* Assume that any device without an ACPI LID device also doesn't
+        * have an integrated LVDS.  We would be better off parsing the BIOS
+        * to get a reliable indicator, but that code isn't written yet.
+        *
+        * In the case of all-in-one desktops using LVDS that we've seen,
+        * they're using SDVO LVDS.
+        */
+       if (!intel_lid_present())
+               return;
+
        if (IS_IGDNG(dev)) {
                if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
                        return;
index f03473779feb4044dfabb08f3c0d7f07cd11ca98..4f0c30948bc43ae5626f1fa76b4368db7f2149ba 100644 (file)
@@ -68,11 +68,22 @@ struct intel_sdvo_priv {
         * This is set if we treat the device as HDMI, instead of DVI.
         */
        bool is_hdmi;
+
        /**
         * This is set if we detect output of sdvo device as LVDS.
         */
        bool is_lvds;
 
+       /**
+        * This is sdvo flags for input timing.
+        */
+       uint8_t sdvo_flags;
+
+       /**
+        * This is sdvo fixed pannel mode pointer
+        */
+       struct drm_display_mode *sdvo_lvds_fixed_mode;
+
        /**
         * Returned SDTV resolutions allowed for the current format, if the
         * device reported it.
@@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
                                         uint16_t height)
 {
        struct intel_sdvo_preferred_input_timing_args args;
+       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
        uint8_t status;
 
        memset(&args, 0, sizeof(args));
@@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
        args.width = width;
        args.height = height;
        args.interlace = 0;
-       args.scaled = 0;
+
+       if (sdvo_priv->is_lvds &&
+          (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width ||
+           sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
+               args.scaled = 1;
+
        intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
                             &args, sizeof(args));
        status = intel_sdvo_read_response(output, NULL, 0);
@@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
        struct intel_output *output = enc_to_intel_output(encoder);
        struct intel_sdvo_priv *dev_priv = output->dev_priv;
 
-       if (!dev_priv->is_tv) {
-               /* Make the CRTC code factor in the SDVO pixel multiplier.  The
-                * SDVO device will be told of the multiplier during mode_set.
-                */
-               adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
-       } else {
+       if (dev_priv->is_tv) {
                struct intel_sdvo_dtd output_dtd;
                bool success;
 
@@ -980,6 +992,47 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                        intel_sdvo_get_preferred_input_timing(output,
                                                             &input_dtd);
                        intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+                       dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
+
+                       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+                       mode->clock = adjusted_mode->clock;
+
+                       adjusted_mode->clock *=
+                               intel_sdvo_get_pixel_multiplier(mode);
+               } else {
+                       return false;
+               }
+       } else if (dev_priv->is_lvds) {
+               struct intel_sdvo_dtd output_dtd;
+               bool success;
+
+               drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0);
+               /* Set output timings */
+               intel_sdvo_get_dtd_from_mode(&output_dtd,
+                               dev_priv->sdvo_lvds_fixed_mode);
+
+               intel_sdvo_set_target_output(output,
+                                            dev_priv->controlled_output);
+               intel_sdvo_set_output_timing(output, &output_dtd);
+
+               /* Set the input timing to the screen. Assume always input 0. */
+               intel_sdvo_set_target_input(output, true, false);
+
+
+               success = intel_sdvo_create_preferred_input_timing(
+                               output,
+                               mode->clock / 10,
+                               mode->hdisplay,
+                               mode->vdisplay);
+
+               if (success) {
+                       struct intel_sdvo_dtd input_dtd;
+
+                       intel_sdvo_get_preferred_input_timing(output,
+                                                            &input_dtd);
+                       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+                       dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
 
                        drm_mode_set_crtcinfo(adjusted_mode, 0);
 
@@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                } else {
                        return false;
                }
+
+       } else {
+               /* Make the CRTC code factor in the SDVO pixel multiplier.  The
+                * SDVO device will be told of the multiplier during mode_set.
+                */
+               adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
        }
        return true;
 }
@@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 
        /* We have tried to get input timing in mode_fixup, and filled into
           adjusted_mode */
-       if (sdvo_priv->is_tv)
+       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
                intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-       else
+               input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
+       } else
                intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
 
        /* If it's a TV, we already set the output timing in mode_fixup.
         * Otherwise, the output timing is equal to the input timing.
         */
-       if (!sdvo_priv->is_tv) {
+       if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
                /* Set the output timing to the screen */
                intel_sdvo_set_target_output(output,
                                             sdvo_priv->controlled_output);
@@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
+       if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
+               sdvox |= SDVO_STALL_SELECT;
        intel_sdvo_write_sdvox(output, sdvox);
 }
 
@@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
        if (sdvo_priv->pixel_clock_max < mode->clock)
                return MODE_CLOCK_HIGH;
 
+       if (sdvo_priv->is_lvds == true) {
+               if (sdvo_priv->sdvo_lvds_fixed_mode == NULL)
+                       return MODE_PANEL;
+
+               if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay)
+                       return MODE_PANEL;
+
+               if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
        return MODE_OK;
 }
 
@@ -1549,6 +1622,8 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       struct drm_display_mode *newmode;
 
        /*
         * Attempt to get the mode list from DDC.
@@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         */
        intel_ddc_get_modes(intel_output);
        if (list_empty(&connector->probed_modes) == false)
-               return;
+               goto end;
 
        /* Fetch modes from VBT */
        if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
-               struct drm_display_mode *newmode;
                newmode = drm_mode_duplicate(connector->dev,
                                             dev_priv->sdvo_lvds_vbt_mode);
                if (newmode != NULL) {
@@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
                        drm_mode_probed_add(connector, newmode);
                }
        }
+
+end:
+       list_for_each_entry(newmode, &connector->probed_modes, head) {
+               if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
+                       sdvo_priv->sdvo_lvds_fixed_mode =
+                               drm_mode_duplicate(connector->dev, newmode);
+                       break;
+               }
+       }
+
 }
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
@@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
 static void intel_sdvo_destroy(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
        if (intel_output->i2c_bus)
                intel_i2c_destroy(intel_output->i2c_bus);
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
 
+       if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
+               drm_mode_destroy(connector->dev,
+                                sdvo_priv->sdvo_lvds_fixed_mode);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
+
        kfree(intel_output);
 }
 
index 193938b7d7f9ea3cce94188fb733a15990282040..ba5cdf8ae40bea4ab9d5b416fd5c3e10ac43facb 100644 (file)
@@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg {
   #define SDVO_HBUF_TX_ONCE    (2 << 6)
   #define SDVO_HBUF_TX_VSYNC   (3 << 6)
 #define SDVO_CMD_GET_AUDIO_TX_INFO     0x9c
+#define SDVO_NEED_TO_STALL  (1 << 7)
 
 struct intel_sdvo_encode{
     u8 dvi_rev;
index 41c907f6c560819b7a1ba651c64334cb4014e025..33de7637c0c63766e4ac933ce5aada21b408a641 100644 (file)
@@ -330,7 +330,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
                goto out_unref;
 
        kmap_offset = dev_offset - bo->vm_node->start;
-       if (unlikely(kmap_offset) >= bo->num_pages) {
+       if (unlikely(kmap_offset >= bo->num_pages)) {
                ret = -EFBIG;
                goto out_unref;
        }
@@ -404,7 +404,7 @@ ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf,
        bool dummy;
 
        kmap_offset = (*f_pos >> PAGE_SHIFT);
-       if (unlikely(kmap_offset) >= bo->num_pages)
+       if (unlikely(kmap_offset >= bo->num_pages))
                return -EFBIG;
 
        page_offset = *f_pos & ~PAGE_MASK;
index c248c1d37268ac64cfed64e8b6bfba43b3d80332..5935b8842e8687c144ec6503b85ae7e9bee81b68 100644 (file)
@@ -183,7 +183,7 @@ int via_enable_vblank(struct drm_device *dev, int crtc)
        }
 
        status = VIA_READ(VIA_REG_INTERRUPT);
-       VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+       VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);
 
        VIA_WRITE8(0x83d4, 0x11);
        VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
@@ -194,6 +194,10 @@ int via_enable_vblank(struct drm_device *dev, int crtc)
 void via_disable_vblank(struct drm_device *dev, int crtc)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
+       u32 status;
+
+       status = VIA_READ(VIA_REG_INTERRUPT);
+       VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);
 
        VIA_WRITE8(0x83d4, 0x11);
        VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
index f2c21d5d24e80e43bc3e482218fd20873f106c07..5eb10c2ce6654b6794041cfd813c95dc01261835 100644 (file)
@@ -1075,14 +1075,16 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);
  */
 int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
 {
-       struct hid_report_enum *report_enum = hid->report_enum + type;
-       struct hid_driver *hdrv = hid->driver;
+       struct hid_report_enum *report_enum;
+       struct hid_driver *hdrv;
        struct hid_report *report;
        unsigned int i;
        int ret;
 
        if (!hid || !hid->driver)
                return -ENODEV;
+       report_enum = hid->report_enum + type;
+       hdrv = hid->driver;
 
        if (!size) {
                dbg_hid("empty report\n");
index 76c4bbe9dccb334ef64359f701321f8fc13df5b3..3c1fcb7640abe1458d52146f8456c16295ec531f 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
index 9e9421525fb9125fa962c2266550f67545855b39..215b2addddbb7c5be5e765dcbe0fd771146129db 100644 (file)
@@ -527,8 +527,10 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
                        goto goodreturn;
 
                case HIDIOCGCOLLECTIONINDEX:
+                       i = field->usage[uref->usage_index].collection_index;
+                       unlock_kernel();
                        kfree(uref_multi);
-                       return field->usage[uref->usage_index].collection_index;
+                       return i;
                case HIDIOCGUSAGES:
                        for (i = 0; i < uref_multi->num_values; i++)
                                uref_multi->values[i] =
index ad2b3431b7253091505e726a72d4857b6f708dde..7d3f15d32fdfee8c1829d0f985cbb46331e7fbfa 100644 (file)
@@ -357,7 +357,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX5 Fan",           39, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x0014, NULL /* Abit AB9 Pro, need DMI string */, {
+       { 0x0014, "AB9", /* + AB9 Pro */ {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR",                 1, 0, 10, 1, 0 },
                { "DDR VTT",             2, 0, 10, 1, 0 },
@@ -455,7 +455,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX3 FAN",           37, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x0018, NULL /* Unknown, need DMI string */, {
+       { 0x0018, "AB9 QuadGT", {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR2",                1, 0, 20, 1, 0 },
                { "DDR2 VTT",            2, 0, 10, 1, 0 },
@@ -564,7 +564,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
                { "AUX3 Fan",           36, 2, 60, 1, 0 },
                { NULL, 0, 0, 0, 0, 0 } }
        },
-       { 0x001C, NULL /* Unknown, need DMI string */, {
+       { 0x001C, "IX38 QuadGT", {
                { "CPU Core",            0, 0, 10, 1, 0 },
                { "DDR2",                1, 0, 20, 1, 0 },
                { "DDR2 VTT",            2, 0, 10, 1, 0 },
index bff0103610c17ada5bf070cb49a5f95871967678..fe4fa29c9219b9884e2e55065728920240a55e14 100644 (file)
@@ -593,7 +593,11 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
        sensor->data = data;
        sensor->id = flags->integer.value;
        sensor->limit1 = limit1->integer.value;
-       sensor->limit2 = limit2->integer.value;
+       if (data->old_interface)
+               sensor->limit2 = limit2->integer.value;
+       else
+               /* The upper limit is expressed as delta from lower limit */
+               sensor->limit2 = sensor->limit1 + limit2->integer.value;
 
        snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
                        "%s%d_input", base_name, start + *num);
index 86142a858238b8ddc0ccf65282ef56e34bd0b8ff..58f66be61b1fbb5e91498c87829b8c912cedc5bc 100644 (file)
@@ -418,6 +418,7 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
                data->count = 3;
                break;
        default:
+               mutex_unlock(&data->update_lock);
                dev_err(&client->dev,
                        "illegal value for fan divider (%d)\n", div);
                return -EINVAL;
index 56cd6004da36e1ec08f94e05b890f61239323c08..6290a259456e8fbae6d5df180cd9825033b46217 100644 (file)
@@ -257,7 +257,7 @@ static inline int sht15_update_single_val(struct sht15_data *data,
                                 (data->flag == SHT15_READING_NOTHING),
                                 msecs_to_jiffies(timeout_msecs));
        if (ret == 0) {/* timeout occurred */
-               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));;
+               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
                sht15_connection_reset(data);
                return -ETIME;
        }
index a92dbb97ee999255e1ad3d79da106894e83282ef..ba75bfcf14ceb9a0f4d550091d6804e6bf2da081 100644 (file)
@@ -86,6 +86,7 @@ superio_exit(void)
 #define SUPERIO_REG_ACT                0x30
 #define SUPERIO_REG_BASE       0x60
 #define SUPERIO_REG_DEVID      0x20
+#define SUPERIO_REG_DEVREV     0x21
 
 /* Logical device registers */
 
@@ -429,6 +430,9 @@ static int __init smsc47m1_find(unsigned short *addr,
         * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
         * supports a 3rd fan, and the pin configuration registers are
         * unfortunately different.
+        * The LPC47M233 has the same device id (0x6B) but is not compatible.
+        * We check the high bit of the device revision register to
+        * differentiate them.
         */
        switch (val) {
        case 0x51:
@@ -448,6 +452,13 @@ static int __init smsc47m1_find(unsigned short *addr,
                sio_data->type = smsc47m1;
                break;
        case 0x6B:
+               if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
+                       pr_debug(DRVNAME ": "
+                                "Found SMSC LPC47M233, unsupported\n");
+                       superio_exit();
+                       return -ENODEV;
+               }
+
                pr_info(DRVNAME ": Found SMSC LPC47M292\n");
                sio_data->type = smsc47m2;
                break;
index 3fae3a91ce5b4acb1d6284a838a348229e2d682b..c89687a10835538307212949317042f40042129c 100644 (file)
@@ -187,6 +187,11 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
        davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
        davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
 
+       /* Respond at reserved "SMBus Host" slave address" (and zero);
+        * we seem to have no option to not respond...
+        */
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);
+
        dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
        dev_dbg(dev->dev, "PSC  = %d\n",
                davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
@@ -387,7 +392,7 @@ static void terminate_write(struct davinci_i2c_dev *dev)
        davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
 
        if (!dev->terminate)
-               dev_err(dev->dev, "TDR IRQ while no data to send\n");
+               dev_dbg(dev->dev, "TDR IRQ while no data to send\n");
 }
 
 /*
@@ -473,9 +478,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
                        break;
 
                case DAVINCI_I2C_IVR_AAS:
-                       dev_warn(dev->dev, "Address as slave interrupt\n");
-               }/* switch */
-       }/* while */
+                       dev_dbg(dev->dev, "Address as slave interrupt\n");
+                       break;
+
+               default:
+                       dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat);
+                       break;
+               }
+       }
 
        return count ? IRQ_HANDLED : IRQ_NONE;
 }
@@ -505,7 +515,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+       ioarea = request_mem_region(mem->start, resource_size(mem),
                                    pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "I2C region already claimed\n");
@@ -523,7 +533,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
        dev->irq = irq->start;
        platform_set_drvdata(pdev, dev);
 
-       dev->clk = clk_get(&pdev->dev, "I2CCLK");
+       dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                r = -ENODEV;
                goto err_free_mem;
@@ -568,7 +578,7 @@ err_free_mem:
        put_device(&pdev->dev);
        kfree(dev);
 err_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -591,7 +601,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)
        kfree(dev);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }
 
index ad8d2010c9211cf0f28f9201aa7346662357626b..fdd83277c8a81ac22441ce7ddea5188b0247e34f 100644 (file)
@@ -806,7 +806,7 @@ omap_i2c_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+       ioarea = request_mem_region(mem->start, resource_size(mem),
                        pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "I2C region already claimed\n");
@@ -905,7 +905,7 @@ err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 err_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -925,7 +925,7 @@ omap_i2c_remove(struct platform_device *pdev)
        iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }
 
index 1c01083b01b5ac0bc3f7eac54a657a72fb049ea0..4f3d99cd16927c2d9ae57c6bbda6d3894e5a9f6b 100644 (file)
@@ -563,7 +563,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_irq;
        }
 
-       size = (res->end - res->start) + 1;
+       size = resource_size(res);
 
        pd->reg = ioremap(res->start, size);
        if (pd->reg == NULL) {
index 042fda295f3a557cd56c623a6aab980ae362271e..6407f47bda82db92b5ba2f2926851f774a938e91 100644 (file)
@@ -92,7 +92,7 @@ static int simtec_i2c_probe(struct platform_device *dev)
                goto err;
        }
 
-       size = (res->end-res->start)+1;
+       size = resource_size(res);
 
        pd->ioarea = request_mem_region(res->start, size, dev->name);
        if (pd->ioarea == NULL) {
index 1a9cc135219f4a5ea613c8da9819676cf19da0f4..b96f3025e588245fc498fcaddb78e706bfe03c6e 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/delay.h>
 
 #define TSL2550_DRV_NAME       "tsl2550"
-#define DRIVER_VERSION         "1.1.1"
+#define DRIVER_VERSION         "1.1.2"
 
 /*
  * Defines
@@ -189,13 +189,16 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
        u8 r = 128;
 
        /* Avoid division by 0 and count 1 cannot be greater than count 0 */
-       if (c0 && (c1 <= c0))
-               r = c1 * 128 / c0;
+       if (c1 <= c0)
+               if (c0) {
+                       r = c1 * 128 / c0;
+
+                       /* Calculate LUX */
+                       lux = ((c0 - c1) * ratio_lut[r]) / 256;
+               } else
+                       lux = 0;
        else
-               return -1;
-
-       /* Calculate LUX */
-       lux = ((c0 - c1) * ratio_lut[r]) / 256;
+               return -EAGAIN;
 
        /* LUX range check */
        return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
index 695181120cdb9f14d0a16740c901345d599d052b..7f878017b736fcd913cfaea1e3939f10bb6cdf82 100644 (file)
@@ -455,6 +455,7 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 
        rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
        rq->special = cmd;
+       cmd->rq = rq;
 }
 
 ide_devset_get(multcount, mult_count);
index 013dc595fab63754b391b33a7efd6b3e287167c3..bc5fb12b913c365da7610365c2167b7a7820e4de 100644 (file)
@@ -1064,6 +1064,7 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
                tape->best_dsc_rw_freq = config.dsc_rw_frequency;
                break;
        case 0x0350:
+               memset(&config, 0, sizeof(config));
                config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
                config.nr_stages = 1;
                if (copy_to_user(argp, &config, sizeof(config)))
index 114efd8dc8f585cfc389dfbb28d11c3c0cd0d3fb..1148140d08a1faf72967dc3068e41c71488054d8 100644 (file)
@@ -608,8 +608,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                                                    p, compat_mode);
 
                        if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
-                               return str_to_user(dev_name(&evdev->dev),
-                                                  _IOC_SIZE(cmd), p);
+                               return str_to_user(dev->name, _IOC_SIZE(cmd), p);
 
                        if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
                                return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
index 0e12f89276a370e753ccbb9e111030f5f83ae253..4cfd084fa8972dda828fa59197eee7e383a03d0c 100644 (file)
@@ -536,7 +536,7 @@ static int joydev_ioctl_common(struct joydev *joydev,
        default:
                if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
                        int len;
-                       const char *name = dev_name(&dev->dev);
+                       const char *name = dev->name;
 
                        if (!name)
                                return 0;
index b868b8d5fbb3e29c58a78c69f5350098fd9ed6f2..f155ad8cdae7e16b8240b20c95c983be24536c41 100644 (file)
@@ -470,20 +470,20 @@ static void xpad_irq_out(struct urb *urb)
        status = urb->status;
 
        switch (status) {
-               case 0:
+       case 0:
                /* success */
-               break;
-               case -ECONNRESET:
-               case -ENOENT:
-               case -ESHUTDOWN:
-                       /* this urb is terminated, clean up */
-                       dbg("%s - urb shutting down with status: %d",
-                               __func__, status);
-                       return;
-               default:
-                       dbg("%s - nonzero urb status received: %d",
-                               __func__, status);
-                       goto exit;
+               return;
+
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __func__, status);
+               return;
+
+       default:
+               dbg("%s - nonzero urb status received: %d", __func__, status);
+               goto exit;
        }
 
 exit:
index df3f8aa68115c48109739f84df30eee651a8ef4e..95fe0452dae48e809d4c7c6db9dab80fae57d127 100644 (file)
@@ -894,6 +894,13 @@ static unsigned int atkbd_amilo_pa1510_forced_release_keys[] = {
        0xb0, 0xae, -1U
 };
 
+/*
+ * Amilo Pi 3525 key release for Fn+Volume keys not working
+ */
+static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
+       0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
+};
+
 /*
  * Amilo Xi 3650 key release for light touch bar not working
  */
@@ -901,6 +908,13 @@ static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
        0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
 };
 
+/*
+ * Soltech TA12 system with broken key release on volume keys and mute key
+ */
+static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
+       0xa0, 0xae, 0xb0, -1U
+};
+
 /*
  * atkbd_set_keycode_table() initializes keyboard's keycode table
  * according to the selected scancode set
@@ -1567,6 +1581,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .callback = atkbd_setup_forced_release,
                .driver_data = atkbd_amilo_pa1510_forced_release_keys,
        },
+       {
+               .ident = "Fujitsu Amilo Pi 3525",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
+               },
+               .callback = atkbd_setup_forced_release,
+               .driver_data = atkbd_amilo_pi3525_forced_release_keys,
+       },
        {
                .ident = "Fujitsu Amilo Xi 3650",
                .matches = {
@@ -1576,6 +1599,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .callback = atkbd_setup_forced_release,
                .driver_data = atkbd_amilo_xi3650_forced_release_keys,
        },
+       {
+               .ident = "Soltech Corporation TA12",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
+               },
+               .callback = atkbd_setup_forced_release,
+               .driver_data = atkdb_soltech_ta12_forced_release_keys,
+       },
        { }
 };
 
index 6d67af5387adcfdff514133ca9f1ce9d0bf39f8b..21cb755a54fb925deda36db17933a0991bb0969c 100644 (file)
@@ -114,7 +114,7 @@ static int __devexit pcspkr_remove(struct platform_device *dev)
        return 0;
 }
 
-static int pcspkr_suspend(struct platform_device *dev, pm_message_t state)
+static int pcspkr_suspend(struct device *dev)
 {
        pcspkr_event(NULL, EV_SND, SND_BELL, 0);
 
@@ -127,14 +127,18 @@ static void pcspkr_shutdown(struct platform_device *dev)
        pcspkr_event(NULL, EV_SND, SND_BELL, 0);
 }
 
+static struct dev_pm_ops pcspkr_pm_ops = {
+       .suspend = pcspkr_suspend,
+};
+
 static struct platform_driver pcspkr_platform_driver = {
        .driver         = {
                .name   = "pcspkr",
                .owner  = THIS_MODULE,
+               .pm     = &pcspkr_pm_ops,
        },
        .probe          = pcspkr_probe,
        .remove         = __devexit_p(pcspkr_remove),
-       .suspend        = pcspkr_suspend,
        .shutdown       = pcspkr_shutdown,
 };
 
index 7c8957dd22c03d42252e410af97e385c78b2c4b7..26e17a9a22eb7fd030edba83537a6d3b68749081 100644 (file)
@@ -644,6 +644,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                },
                .driver_data = keymap_fs_amilo_pro_v2000
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Maxdata Pro 7000 DX",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
+               },
+               .driver_data = keymap_fs_amilo_pro_v2000
+       },
        {
                .callback = dmi_matched,
                .ident = "Fujitsu N3510",
index 1ebfcab746623d8fd09acf35d6b753afc0963c12..8ff7e35c70696de765b8ab3dc2e4b61a02ee3356 100644 (file)
@@ -408,6 +408,8 @@ static int if_write_room(struct tty_struct *tty)
        return retval;
 }
 
+/* FIXME: This function does not have error returns */
+
 static int if_chars_in_buffer(struct tty_struct *tty)
 {
        struct cardstate *cs;
index 8df889b0c1a97b1a6c3546545840bc3279755486..9de54202c90c84828c86cefeeb3408b090ea0bdc 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/moduleparam.h>
 #include "hisax.h"
index b4d4522e50718347f02b88345cc93d50608d9252..2881a66c1aa97c2e78e0c9f3029bbbd44ef0046a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/isdn.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #ifdef CONFIG_ISDN_AUDIO
index 990e6a7e6674dce0c866083fc576ce8acb1d9e52..c3b661a666cbb97478033040bb2f6bf245129208 100644 (file)
@@ -731,10 +731,10 @@ l1oip_socket_thread(void *data)
        while (!signal_pending(current)) {
                struct kvec iov = {
                        .iov_base = recvbuf,
-                       .iov_len = sizeof(recvbuf),
+                       .iov_len = recvbuf_size,
                };
                recvlen = kernel_recvmsg(socket, &msg, &iov, 1,
-                                        sizeof(recvbuf), 0);
+                                        recvbuf_size, 0);
                if (recvlen > 0) {
                        l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
                } else {
index e2f45019ebf0be504bdcd68538cd47f51109c588..3e1532a180ff172df2c92f2c19e8bb3ecdc9f1cd 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/mISDNif.h>
 #include <linux/kthread.h>
+#include <linux/smp_lock.h>
 #include "core.h"
 
 static u_int   *debug;
index 9c3138265f8e4fa62892321c97cd62d88c52584c..01c591923793f4d494fffef7d86a17f0da43f479 100644 (file)
@@ -38,8 +38,6 @@ struct lguest_pages
 #define CHANGED_GDT_TLS                4 /* Actually a subset of CHANGED_GDT */
 #define CHANGED_ALL            3
 
-struct lguest;
-
 struct lg_cpu {
        unsigned int id;
        struct lguest *lg;
index 9933eb861c7191b34fe43b9ac01deb5e44bd614f..ed1038164019a1d5935937037c6aae2bd429c666 100644 (file)
@@ -776,7 +776,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                 * But don't wait if split was due to the io size restriction
                 */
                if (unlikely(out_of_pages))
-                       congestion_wait(WRITE, HZ/100);
+                       congestion_wait(BLK_RW_ASYNC, HZ/100);
 
                /*
                 * With async crypto it is unsafe to share the crypto context
@@ -1318,7 +1318,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
 {
        struct crypt_config *cc = ti->private;
 
-       return fn(ti, cc->dev, cc->start, data);
+       return fn(ti, cc->dev, cc->start, ti->len, data);
 }
 
 static struct target_type crypt_target = {
index 4e5b843cd4d77fb388920991eefd5540e2399aef..ebe7381f47c8fd5b1d86cd4e603acad20eebe98f 100644 (file)
@@ -324,12 +324,12 @@ static int delay_iterate_devices(struct dm_target *ti,
        struct delay_c *dc = ti->private;
        int ret = 0;
 
-       ret = fn(ti, dc->dev_read, dc->start_read, data);
+       ret = fn(ti, dc->dev_read, dc->start_read, ti->len, data);
        if (ret)
                goto out;
 
        if (dc->dev_write)
-               ret = fn(ti, dc->dev_write, dc->start_write, data);
+               ret = fn(ti, dc->dev_write, dc->start_write, ti->len, data);
 
 out:
        return ret;
index 9184b6deb8685dc3660e21dd438f6aa8fcd200b3..82f7d6e6b1eab551588ae6b8e917622151c4d4ff 100644 (file)
@@ -139,7 +139,7 @@ static int linear_iterate_devices(struct dm_target *ti,
 {
        struct linear_c *lc = ti->private;
 
-       return fn(ti, lc->dev, lc->start, data);
+       return fn(ti, lc->dev, lc->start, ti->len, data);
 }
 
 static struct target_type linear_target = {
index c70604a208979b4b1f87e4a9e98f10b5ce00036d..6f0d90d4a541962e0ba289e5e2568da51d6445cb 100644 (file)
@@ -1453,7 +1453,7 @@ static int multipath_iterate_devices(struct dm_target *ti,
 
        list_for_each_entry(pg, &m->priority_groups, list) {
                list_for_each_entry(p, &pg->pgpaths, list) {
-                       ret = fn(ti, p->path.dev, ti->begin, data);
+                       ret = fn(ti, p->path.dev, ti->begin, ti->len, data);
                        if (ret)
                                goto out;
                }
index ce8868c768cce1c411d3ba76d4eae5b9011bee64..9726577cde493f2ca21b7fd28386d1d2a31c8786 100644 (file)
@@ -638,6 +638,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
                spin_lock_irq(&ms->lock);
                bio_list_merge(&ms->writes, &requeue);
                spin_unlock_irq(&ms->lock);
+               delayed_wake(ms);
        }
 
        /*
@@ -1292,7 +1293,7 @@ static int mirror_iterate_devices(struct dm_target *ti,
 
        for (i = 0; !ret && i < ms->nr_mirrors; i++)
                ret = fn(ti, ms->mirror[i].dev,
-                        ms->mirror[i].offset, data);
+                        ms->mirror[i].offset, ti->len, data);
 
        return ret;
 }
index b240e85ae39aa4b444135b0a71823e35b03aac49..4e0e5937e42afc6f35274fc8856c3a8190cd1c20 100644 (file)
@@ -320,10 +320,11 @@ static int stripe_iterate_devices(struct dm_target *ti,
        int ret = 0;
        unsigned i = 0;
 
-       do
+       do {
                ret = fn(ti, sc->stripe[i].dev,
-                        sc->stripe[i].physical_start, data);
-       while (!ret && ++i < sc->stripes);
+                        sc->stripe[i].physical_start,
+                        sc->stripe_width, data);
+       } while (!ret && ++i < sc->stripes);
 
        return ret;
 }
index 2cba557d9e61e10dad844dea12f134b4a4ee0d11..d952b3441913a74b15c09f6ba7ea6237bd1e8aa0 100644 (file)
@@ -346,7 +346,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
  * If possible, this checks an area of a destination device is valid.
  */
 static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
-                               sector_t start, void *data)
+                               sector_t start, sector_t len, void *data)
 {
        struct queue_limits *limits = data;
        struct block_device *bdev = dev->bdev;
@@ -359,7 +359,7 @@ static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
        if (!dev_size)
                return 1;
 
-       if ((start >= dev_size) || (start + ti->len > dev_size)) {
+       if ((start >= dev_size) || (start + len > dev_size)) {
                DMWARN("%s: %s too small for target",
                       dm_device_name(ti->table->md), bdevname(bdev, b));
                return 0;
@@ -377,11 +377,11 @@ static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
                return 0;
        }
 
-       if (ti->len & (logical_block_size_sectors - 1)) {
+       if (len & (logical_block_size_sectors - 1)) {
                DMWARN("%s: len=%llu not aligned to h/w "
                       "logical block size %hu of %s",
                       dm_device_name(ti->table->md),
-                      (unsigned long long)ti->len,
+                      (unsigned long long)len,
                       limits->logical_block_size, bdevname(bdev, b));
                return 0;
        }
@@ -482,7 +482,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
 #define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
 
 int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
-                        sector_t start, void *data)
+                        sector_t start, sector_t len, void *data)
 {
        struct queue_limits *limits = data;
        struct block_device *bdev = dev->bdev;
@@ -830,11 +830,6 @@ unsigned dm_table_get_type(struct dm_table *t)
        return t->type;
 }
 
-bool dm_table_bio_based(struct dm_table *t)
-{
-       return dm_table_get_type(t) == DM_TYPE_BIO_BASED;
-}
-
 bool dm_table_request_based(struct dm_table *t)
 {
        return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
index 9acd54a5cffb3b875c699332c0bfaf597be3d19a..8a311ea0d441faad7b5fdf2d0ce9a34a3d01983d 100644 (file)
@@ -2203,16 +2203,6 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
                goto out;
        }
 
-       /*
-        * It is enought that blk_queue_ordered() is called only once when
-        * the first bio-based table is bound.
-        *
-        * This setting should be moved to alloc_dev() when request-based dm
-        * supports barrier.
-        */
-       if (!md->map && dm_table_bio_based(table))
-               blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
-
        __unbind(md);
        r = __bind(md, table, &limits);
 
index 23278ae80f08dfc90c8458a3b6a700e4a2a87f8b..a7663eba17e2920ba84d5a7f41fe5fa015964590 100644 (file)
@@ -61,7 +61,6 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits);
 int dm_table_any_busy_target(struct dm_table *t);
 int dm_table_set_type(struct dm_table *t);
 unsigned dm_table_get_type(struct dm_table *t);
-bool dm_table_bio_based(struct dm_table *t);
 bool dm_table_request_based(struct dm_table *t);
 int dm_table_alloc_md_mempools(struct dm_table *t);
 void dm_table_free_md_mempools(struct dm_table *t);
index efb4a6c2b57a5d39cf9c70a5cef455a9dbb528e4..9a6307a347b21e7169a41f4f4a9d1ecbce15dd3f 100644 (file)
 #include "tuner-simple.h"
 #include "stv0297.h"
 
+
+/* Can we use the specified front-end?  Remember that if we are compiled
+ * into the kernel we can't call code that's in modules.  */
+#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
+       (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
+
 /* lnb control */
-#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
+#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct flexcop_device *fc = fe->dvb->priv;
@@ -49,8 +55,7 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
 }
 #endif
 
-#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
-       || defined(CONFIG_DVB_MT312_MODULE)
+#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
 static int flexcop_sleep(struct dvb_frontend* fe)
 {
        struct flexcop_device *fc = fe->dvb->priv;
@@ -61,7 +66,7 @@ static int flexcop_sleep(struct dvb_frontend* fe)
 #endif
 
 /* SkyStar2 DVB-S rev 2.3 */
-#if defined(CONFIG_DVB_MT312_MODULE)
+#if FE_SUPPORTED(MT312)
 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
 /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
@@ -193,10 +198,12 @@ static int skystar2_rev23_attach(struct flexcop_device *fc,
        }
        return 0;
 }
+#else
+#define skystar2_rev23_attach NULL
 #endif
 
 /* SkyStar2 DVB-S rev 2.6 */
-#if defined(CONFIG_DVB_STV0299_MODULE)
+#if FE_SUPPORTED(STV0299)
 static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
        u32 srate, u32 ratio)
 {
@@ -321,10 +328,12 @@ static int skystar2_rev26_attach(struct flexcop_device *fc,
        }
        return 0;
 }
+#else
+#define skystar2_rev26_attach NULL
 #endif
 
 /* SkyStar2 DVB-S rev 2.7 */
-#if defined(CONFIG_DVB_S5H1420_MODULE)
+#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
 static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
        .demod_address = 0x53,
        .invert = 1,
@@ -385,10 +394,12 @@ fail:
        fc->fc_i2c_adap[0].no_base_addr = 0;
        return 0;
 }
+#else
+#define skystar2_rev27_attach NULL
 #endif
 
 /* SkyStar2 rev 2.8 */
-#if defined(CONFIG_DVB_CX24123_MODULE)
+#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
 static struct cx24123_config skystar2_rev2_8_cx24123_config = {
        .demod_address = 0x55,
        .dont_use_pll = 1,
@@ -433,10 +444,12 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
         * IR-receiver (PIC16F818) - but the card has no input for that ??? */
        return 1;
 }
+#else
+#define skystar2_rev28_attach NULL
 #endif
 
 /* AirStar DVB-T */
-#if defined(CONFIG_DVB_MT352_MODULE)
+#if FE_SUPPORTED(MT352)
 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
 {
        static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
@@ -495,10 +508,12 @@ static int airstar_dvbt_attach(struct flexcop_device *fc,
        }
        return 0;
 }
+#else
+#define airstar_dvbt_attach NULL
 #endif
 
 /* AirStar ATSC 1st generation */
-#if defined(CONFIG_DVB_BCM3510_MODULE)
+#if FE_SUPPORTED(BCM3510)
 static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
        const struct firmware **fw, char* name)
 {
@@ -517,10 +532,12 @@ static int airstar_atsc1_attach(struct flexcop_device *fc,
        fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
        return fc->fe != NULL;
 }
+#else
+#define airstar_atsc1_attach NULL
 #endif
 
 /* AirStar ATSC 2nd generation */
-#if defined(CONFIG_DVB_NXT200X_MODULE)
+#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
 static struct nxt200x_config samsung_tbmv_config = {
        .demod_address = 0x0a,
 };
@@ -535,10 +552,12 @@ static int airstar_atsc2_attach(struct flexcop_device *fc,
        return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
                            DVB_PLL_SAMSUNG_TBMV);
 }
+#else
+#define airstar_atsc2_attach NULL
 #endif
 
 /* AirStar ATSC 3rd generation */
-#if defined(CONFIG_DVB_LGDT330X_MODULE)
+#if FE_SUPPORTED(LGDT330X)
 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
        .demod_address       = 0x59,
        .demod_chip          = LGDT3303,
@@ -556,10 +575,12 @@ static int airstar_atsc3_attach(struct flexcop_device *fc,
        return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
                            TUNER_LG_TDVS_H06XF);
 }
+#else
+#define airstar_atsc3_attach NULL
 #endif
 
 /* CableStar2 DVB-C */
-#if defined(CONFIG_DVB_STV0297_MODULE)
+#if FE_SUPPORTED(STV0297)
 static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
                struct dvb_frontend_parameters *fep)
 {
@@ -698,39 +719,23 @@ static int cablestar2_attach(struct flexcop_device *fc,
        fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
        return 1;
 }
+#else
+#define cablestar2_attach NULL
 #endif
 
 static struct {
        flexcop_device_type_t type;
        int (*attach)(struct flexcop_device *, struct i2c_adapter *);
 } flexcop_frontends[] = {
-#if defined(CONFIG_DVB_S5H1420_MODULE)
        { FC_SKY_REV27, skystar2_rev27_attach },
-#endif
-#if defined(CONFIG_DVB_CX24123_MODULE)
        { FC_SKY_REV28, skystar2_rev28_attach },
-#endif
-#if defined(CONFIG_DVB_STV0299_MODULE)
        { FC_SKY_REV26, skystar2_rev26_attach },
-#endif
-#if defined(CONFIG_DVB_MT352_MODULE)
        { FC_AIR_DVBT, airstar_dvbt_attach },
-#endif
-#if defined(CONFIG_DVB_NXT200X_MODULE)
        { FC_AIR_ATSC2, airstar_atsc2_attach },
-#endif
-#if defined(CONFIG_DVB_LGDT330X_MODULE)
        { FC_AIR_ATSC3, airstar_atsc3_attach },
-#endif
-#if defined(CONFIG_DVB_BCM3510_MODULE)
        { FC_AIR_ATSC1, airstar_atsc1_attach },
-#endif
-#if defined(CONFIG_DVB_STV0297_MODULE)
        { FC_CABLE, cablestar2_attach },
-#endif
-#if defined(CONFIG_DVB_MT312_MODULE)
        { FC_SKY_REV23, skystar2_rev23_attach },
-#endif
 };
 
 /* try to figure out the frontend */
@@ -738,6 +743,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+               if (!flexcop_frontends[i].attach)
+                       continue;
                /* type needs to be set before, because of some workarounds
                 * done based on the probed card type */
                fc->dev_type = flexcop_frontends[i].type;
index 4601b059b2b20008b7b277f725ec66d207c83e42..0e246eaad05ab441360963e02672945e6d61534b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/dvb/ca.h>
 #include "dvbdev.h"
index 79927305e84d42e63030e720a43c617c7f493b04..487919bea7ae0bf147004b6845611f24eea0537f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 
 #define DVB_MAJOR 212
 
index 136c5863d81b5859d38fefd33b496932e8f6cca5..12e018b4107daec6758c7571ef3bb3bd4e244159 100644 (file)
@@ -527,6 +527,10 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
        u8 i, buf[3] = {0, 0, 0};
        *auto_mode = 0; /* set if parameters are requested to auto set */
 
+       /* Try auto-detect transmission parameters in case of AUTO requested or
+          garbage parameters given by application for compatibility.
+          MPlayer seems to provide garbage parameters currently. */
+
        switch (params->transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
                *auto_mode = 1;
@@ -536,7 +540,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[0] |= (1 << 0);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid transmission_mode\n", __func__);
+               *auto_mode = 1;
        }
 
        switch (params->guard_interval) {
@@ -554,7 +559,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[0] |= (3 << 2);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid guard_interval\n", __func__);
+               *auto_mode = 1;
        }
 
        switch (params->hierarchy_information) {
@@ -572,7 +578,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[0] |= (3 << 4);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid hierarchy_information\n", __func__);
+               *auto_mode = 1;
        };
 
        switch (params->constellation) {
@@ -587,7 +594,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[1] |= (2 << 6);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid constellation\n", __func__);
+               *auto_mode = 1;
        }
 
        /* Use HP. How and which case we can switch to LP? */
@@ -611,7 +619,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[2] |= (4 << 0);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid code_rate_HP\n", __func__);
+               *auto_mode = 1;
        }
 
        switch (params->code_rate_LP) {
@@ -638,7 +647,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                if (params->hierarchy_information == HIERARCHY_AUTO)
                        break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid code_rate_LP\n", __func__);
+               *auto_mode = 1;
        }
 
        switch (params->bandwidth) {
@@ -651,7 +661,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[1] |= (2 << 2);
                break;
        default:
-               return -EINVAL;
+               deb_info("%s: invalid bandwidth\n", __func__);
+               buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */
        }
 
        /* program */
index d1d959ed37b7947562394af311273e0343aec2c6..8d65c652ba5062c5c51765b887ea82ddb616f6f0 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 837467f93805e9c2f32b37c0f71cce6d3852ffef..575bf9d894193f83d465ced201bad022f1fb87b6 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
index 46d21632961138d76be607c02b672b34714a4d61..e85f318b4d2b4131ff00395e61d17c66eeeecc18 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
index fdb4adff3d287dd41b0777f9843321cf0c8682ea..ca6558c394be0c97484bc5f67093c9e3962bfe24 100644 (file)
@@ -3324,8 +3324,6 @@ void __devinit bttv_init_card1(struct bttv *btv)
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-       int addr=ADDR_UNSET;
-
        btv->tuner_type = UNSET;
 
        if (BTTV_BOARD_UNKNOWN == btv->c.type) {
@@ -3470,9 +3468,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
        btv->pll.pll_current = -1;
 
        /* tuner configuration (from card list / autodetect / insmod option) */
-       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
-               addr = bttv_tvcards[btv->c.type].tuner_addr;
-
        if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
                if (UNSET == btv->tuner_type)
                        btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
@@ -3496,40 +3491,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (UNSET == btv->tuner_type)
                btv->tuner_type = TUNER_ABSENT;
 
-       if (btv->tuner_type != TUNER_ABSENT) {
-               struct tuner_setup tun_setup;
-
-               /* Load tuner module before issuing tuner config call! */
-               if (bttv_tvcards[btv->c.type].has_radio)
-                       v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
-                               v4l2_i2c_tuner_addrs(ADDRS_RADIO));
-               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
-                               v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
-               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
-                               &btv->c.i2c_adap, "tuner", "tuner",
-                               v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
-
-               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
-               tun_setup.type = btv->tuner_type;
-               tun_setup.addr = addr;
-
-               if (bttv_tvcards[btv->c.type].has_radio)
-                       tun_setup.mode_mask |= T_RADIO;
-
-               bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
-       }
-
-       if (btv->tda9887_conf) {
-               struct v4l2_priv_tun_config tda9887_cfg;
-
-               tda9887_cfg.tuner = TUNER_TDA9887;
-               tda9887_cfg.priv = &btv->tda9887_conf;
-
-               bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
-       }
-
        btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
                   bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET;
        btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ?
@@ -3540,15 +3501,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->has_remote = remote[btv->c.nr];
 
        if (bttv_tvcards[btv->c.type].has_radio)
-               btv->has_radio=1;
+               btv->has_radio = 1;
        if (bttv_tvcards[btv->c.type].has_remote)
-               btv->has_remote=1;
+               btv->has_remote = 1;
        if (!bttv_tvcards[btv->c.type].no_gpioirq)
-               btv->gpioirq=1;
+               btv->gpioirq = 1;
        if (bttv_tvcards[btv->c.type].volume_gpio)
-               btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
+               btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio;
        if (bttv_tvcards[btv->c.type].audio_mode_gpio)
-               btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
+               btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio;
 
        if (btv->tuner_type == TUNER_ABSENT)
                return;  /* no tuner or related drivers to load */
@@ -3666,6 +3627,49 @@ no_audio:
 }
 
 
+/* initialize the tuner */
+void __devinit bttv_init_tuner(struct bttv *btv)
+{
+       int addr = ADDR_UNSET;
+
+       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+               addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+       if (btv->tuner_type != TUNER_ABSENT) {
+               struct tuner_setup tun_setup;
+
+               /* Load tuner module before issuing tuner config call! */
+               if (bttv_tvcards[btv->c.type].has_radio)
+                       v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+
+               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+               tun_setup.type = btv->tuner_type;
+               tun_setup.addr = addr;
+
+               if (bttv_tvcards[btv->c.type].has_radio)
+                       tun_setup.mode_mask |= T_RADIO;
+
+               bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
+       }
+
+       if (btv->tda9887_conf) {
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &btv->tda9887_conf;
+
+               bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
+       }
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void modtec_eeprom(struct bttv *btv)
index 5eb1464af6703f3825599e05bc4683a2e09dc250..8cc6dd28d6a7a1ca4109064d6d98994d280003a2 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include "bttvp.h"
@@ -4418,6 +4419,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        /* some card-specific stuff (needs working i2c) */
        bttv_init_card2(btv);
+       bttv_init_tuner(btv);
        init_irqreg(btv);
 
        /* register video4linux + input */
index 3d36daf206f37a3c05f3b8466d6a3e2c237de5be..3ec2402c6b4a188ef54260b1f3012bc977d18ee9 100644 (file)
@@ -283,6 +283,7 @@ extern struct tvcard bttv_tvcards[];
 extern void bttv_idcard(struct bttv *btv);
 extern void bttv_init_card1(struct bttv *btv);
 extern void bttv_init_card2(struct bttv *btv);
+extern void bttv_init_tuner(struct bttv *btv);
 
 /* card-specific funtions */
 extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
index 2943bfd32a94a4b74acb19d6a9076abd7e1d3388..e0cf21e0b1bf52e3649841a6405d70ed3c4859ef 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/smp_lock.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cx2341x.h>
@@ -57,7 +58,8 @@ MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
 
 #define dprintk(level, fmt, arg...)\
        do { if (v4l_debug >= level) \
-               printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\
+               printk(KERN_DEBUG "%s: " fmt, \
+               (dev) ? dev->name : "cx23885[?]", ## arg); \
        } while (0)
 
 static struct cx23885_tvnorm cx23885_tvnorms[] = {
@@ -1676,6 +1678,7 @@ static struct v4l2_file_operations mpeg_fops = {
        .read          = mpeg_read,
        .poll          = mpeg_poll,
        .mmap          = mpeg_mmap,
+       .ioctl         = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
index 70836af3ab4891a624a87225d6ec0bf2cdd8cf32..5d6093336300dc79731177dbaada479bcd40fcac 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
index 44eacfb0d0d6073db886168e8d4120f99cd76ae7..356d6896da3f5877e5961fb4d009309fe68cae33 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/smp_lock.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cx2341x.h>
index b12770848c00161e5355fd05c0816fbb9e0c3134..2bb54c3ef5cdcefbc708718aebee684005f80e3d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index ec2f45dde1643d72a849aa15004bbde91a1ff2c3..0664d111085f262db7e621d21f0ed20b41a85856 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
index ebd24a25fb8510043245cacfab39c1e4553ab624..320f1f60276ec0a5fa71f58ba5eca48690d19f1a 100644 (file)
@@ -58,8 +58,6 @@ static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
 
-#define MT9V011_VERSION                 0x8243
-
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
 static unsigned long em28xx_devused;
 
@@ -159,6 +157,20 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
        { -1,                   -1,     -1,             -1},
 };
 
+/* Pinnacle Hybrid Pro eb1a:2881 */
+static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+       {EM28XX_R08_GPIO,       0xfd,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x04,   0xff,          100},/* zl10353 reset */
+       {EM2880_R04_GPO,        0x0c,   0xff,            1},
+       {       -1,             -1,     -1,             -1},
+};
+
+
 /* Callback for the most boards */
 static struct em28xx_reg_seq default_tuner_gpio[] = {
        {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
@@ -205,13 +217,15 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = {
  */
 struct em28xx_board em28xx_boards[] = {
        [EM2750_BOARD_UNKNOWN] = {
-               .name          = "Unknown EM2750/EM2751 webcam grabber",
+               .name          = "EM2710/EM2750/EM2751 webcam grabber",
                .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
-               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
+               .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
                        .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = silvercrest_reg_seq,
                } },
        },
        [EM2800_BOARD_UNKNOWN] = {
@@ -233,13 +247,15 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_UNKNOWN] = {
                .name          = "Unknown EM2750/28xx video grabber",
                .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,     /* To enable sensor probe */
        },
        [EM2750_BOARD_DLCW_130] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
                .name          = "Huaqi DLCW-130",
                .valid         = EM28XX_BOARD_NOT_VALIDATED,
                .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
-               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
+               .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -440,7 +456,8 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
                .name         = "Videology 20K14XUSB USB2.0",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .tuner_type   = TUNER_ABSENT,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -450,8 +467,7 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_SILVERCREST_WEBCAM] = {
                .name         = "Silvercrest Webcam 1.3mpix",
                .tuner_type   = TUNER_ABSENT,
-               .is_27xx      = 1,
-               .decoder      = EM28XX_MT9V011,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -500,7 +516,8 @@ struct em28xx_board em28xx_boards[] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
                .name         = "NetGMBH Cam",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .tuner_type   = TUNER_ABSENT,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -1250,25 +1267,26 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
                .name         = "Pinnacle Hybrid Pro",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
+               .has_dvb      = 1,
+               .dvb_gpio     = pinnacle_hybrid_pro_digital,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = EM28XX_AMUX_VIDEO,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                } },
        },
        [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
@@ -1638,6 +1656,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
        {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
        {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
+       {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
@@ -1704,6 +1723,32 @@ static inline void em28xx_set_model(struct em28xx *dev)
                                       EM28XX_I2C_FREQ_100_KHZ;
 }
 
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+       int i;
+       unsigned char regs[][3] = {
+               { 0x0d, 0x00, 0x01, },
+               { 0x0d, 0x00, 0x00, },
+               { 0x04, 0x05, 0x00, },  /* hres = 1280 */
+               { 0x03, 0x04, 0x00, },  /* vres = 1024 */
+               { 0x20, 0x11, 0x00, },
+               { 0x06, 0x00, 0x10, },
+               { 0x2b, 0x00, 0x24, },
+               { 0x2e, 0x00, 0x24, },
+               { 0x35, 0x00, 0x24, },
+               { 0x2d, 0x00, 0x20, },
+               { 0x2c, 0x00, 0x20, },
+               { 0x09, 0x0a, 0xd4, },
+               { 0x35, 0x00, 0x57, },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
+
+       return 0;
+}
+
 /* HINT method: webcam I2C chips
  *
  * This method work for webcams with Micron sensors
@@ -1716,9 +1761,6 @@ static int em28xx_hint_sensor(struct em28xx *dev)
        __be16 version_be;
        u16 version;
 
-       if (dev->model != EM2820_BOARD_UNKNOWN)
-               return 0;
-
        dev->i2c_client.addr = 0xba >> 1;
        cmd = 0;
        i2c_master_send(&dev->i2c_client, &cmd, 1);
@@ -1729,16 +1771,38 @@ static int em28xx_hint_sensor(struct em28xx *dev)
        version = be16_to_cpu(version_be);
 
        switch (version) {
-       case MT9V011_VERSION:
+       case 0x8243:            /* mt9v011 640x480 1.3 Mpix sensor */
                dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
                sensor_name = "mt9v011";
+               dev->em28xx_sensor = EM28XX_MT9V011;
+               dev->sensor_xres = 640;
+               dev->sensor_yres = 480;
+               dev->sensor_xtal = 6300000;
+
+               /* probably means GRGB 16 bit bayer */
+               dev->vinmode = 0x0d;
+               dev->vinctl = 0x00;
+
+               break;
+       case 0x8431:
+               dev->model = EM2750_BOARD_UNKNOWN;
+               sensor_name = "mt9m001";
+               dev->em28xx_sensor = EM28XX_MT9M001;
+               em28xx_initialize_mt9m001(dev);
+               dev->sensor_xres = 1280;
+               dev->sensor_yres = 1024;
+
+               /* probably means BGGR 16 bit bayer */
+               dev->vinmode = 0x0c;
+               dev->vinctl = 0x00;
+
                break;
        default:
-               printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version));
+               printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version));
                return -EINVAL;
        }
 
-       em28xx_errdev("Sensor is %s, assuming that webcam is %s\n",
+       em28xx_errdev("Sensor is %s, using model %s entry.\n",
                      sensor_name, em28xx_boards[dev->model].name);
 
        return 0;
@@ -1772,10 +1836,7 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                        em28xx_info("chip ID is em2750\n");
                        break;
                case CHIP_ID_EM2820:
-                       if (dev->board.is_27xx)
-                               em28xx_info("chip is em2710\n");
-                       else
-                               em28xx_info("chip ID is em2820\n");
+                       em28xx_info("chip ID is em2710 or em2820\n");
                        break;
                case CHIP_ID_EM2840:
                        em28xx_info("chip ID is em2840\n");
@@ -1929,6 +1990,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
@@ -2225,6 +2287,7 @@ void em28xx_card_setup(struct em28xx *dev)
                   em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
                   so make the call now so the analog GPIOs are set properly
                   before probing the i2c bus. */
+               em28xx_gpio_set(dev, dev->board.tuner_gpio);
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                break;
        case EM2820_BOARD_SILVERCREST_WEBCAM:
@@ -2262,9 +2325,14 @@ void em28xx_card_setup(struct em28xx *dev)
                v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                        "tvp5150", "tvp5150", tvp5150_addrs);
 
-       if (dev->board.decoder == EM28XX_MT9V011)
-               v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
-                       "mt9v011", "mt9v011", mt9v011_addrs);
+       if (dev->em28xx_sensor == EM28XX_MT9V011) {
+               struct v4l2_subdev *sd;
+
+               sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+                        &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs);
+               v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+       }
+
 
        if (dev->board.adecoder == EM28XX_TVAUDIO)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
@@ -2410,7 +2478,19 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                return errCode;
        }
 
-       em28xx_hint_sensor(dev);
+       /*
+        * Default format, used for tvp5150 or saa711x output formats
+        */
+       dev->vinmode = 0x10;
+       dev->vinctl  = 0x11;
+
+       /*
+        * If the device can be a webcam, seek for a sensor.
+        * If sensor is not found, then it isn't a webcam.
+        */
+       if (dev->board.is_webcam)
+               if (em28xx_hint_sensor(dev) < 0)
+                       dev->board.is_webcam = 0;
 
        /* Do board specific init and eeprom reading */
        em28xx_card_setup(dev);
index 079ab4d563a62c4a41b6db6ff9d3df70a03a4e26..5b78e199abd1ac9bbf433dba0012eafe02b0ab46 100644 (file)
@@ -648,28 +648,17 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 int em28xx_set_outfmt(struct em28xx *dev)
 {
        int ret;
-       int vinmode, vinctl, outfmt;
-
-       outfmt  = dev->format->reg;
-
-       if (dev->board.is_27xx) {
-               vinmode = 0x0d;
-               vinctl  = 0x00;
-       } else {
-               vinmode = 0x10;
-               vinctl  = 0x11;
-       }
 
        ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
-                               outfmt | 0x20, 0xff);
+                               dev->format->reg | 0x20, 0xff);
        if (ret < 0)
                        return ret;
 
-       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode);
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
        if (ret < 0)
                return ret;
 
-       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl);
+       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl);
 }
 
 static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -707,10 +696,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
        u8 mode;
        /* the em2800 scaler only supports scaling down to 50% */
 
-       if (dev->board.is_27xx) {
-               /* FIXME: Don't use the scaler yet */
-               mode = 0;
-       } else if (dev->board.is_em2800) {
+       if (dev->board.is_em2800) {
                mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
        } else {
                u8 buf[2];
index 3da97c32b8fad9ee2c315572143ba52fa217eef2..cf0ac7f2a30d59bed6a8e617a1a1ea38e0e3e6d5 100644 (file)
@@ -31,6 +31,8 @@
 #include "lgdt330x.h"
 #include "zl10353.h"
 #include "s5h1409.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -243,7 +245,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 };
 
-static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = {
+static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
        .disable_i2c_gate_ctrl = 1,
@@ -258,6 +260,41 @@ static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
 };
 #endif
 
+static int mt352_terratec_xs_init(struct dvb_frontend *fe)
+{
+       /* Values extracted from a USB trace of the Terratec Windows driver */
+       static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
+       static u8 reset[]          = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
+       static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
+       static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+       static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
+       static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
+       static u8 tuner_go[]       = { TUNER_GO, 0x01};
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
+       mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+       mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
+       mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
+       mt352_write(fe, tuner_go,       sizeof(tuner_go));
+       return 0;
+}
+
+static struct mt352_config terratec_xs_mt352_cfg = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner = 1,
+       .if2 = 45600,
+       .demod_init = mt352_terratec_xs_init,
+};
+
 /* ------------------------------------------------------------------ */
 
 static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -440,7 +477,6 @@ static int dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
-       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
        case EM2880_BOARD_KWORLD_DVB_310U:
        case EM2880_BOARD_EMPIRE_DUAL_TV:
                dvb->frontend = dvb_attach(zl10353_attach,
@@ -451,20 +487,28 @@ static int dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+               dvb->frontend = dvb_attach(zl10353_attach,
+                                          &em28xx_zl10353_xc3028_no_i2c_gate,
+                                          &dev->i2c_adap);
+               if (attach_xc3028(0x61, dev) < 0) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
                dvb->frontend = dvb_attach(zl10353_attach,
-                                          &em28xx_terratec_xs_zl10353_xc3028,
+                                          &em28xx_zl10353_xc3028_no_i2c_gate,
                                           &dev->i2c_adap);
                if (dvb->frontend == NULL) {
                        /* This board could have either a zl10353 or a mt352.
                           If the chip id isn't for zl10353, try mt352 */
-
-                       /* FIXME: make support for mt352 work */
-                       printk(KERN_ERR "version of this board with mt352 not "
-                              "currently supported\n");
-                       result = -EINVAL;
-                       goto out_free;
+                       dvb->frontend = dvb_attach(mt352_attach,
+                                                  &terratec_xs_mt352_cfg,
+                                                  &dev->i2c_adap);
                }
+
                if (attach_xc3028(0x61, dev) < 0) {
                        result = -EINVAL;
                        goto out_free;
index 14316c912179ab32b6b2ad456f10c83b66729d22..ff37b4c15f444e43c54034622113384ac8f498e0 100644 (file)
@@ -657,8 +657,8 @@ static void get_scale(struct em28xx *dev,
                        unsigned int width, unsigned int height,
                        unsigned int *hscale, unsigned int *vscale)
 {
-       unsigned int          maxw   = norm_maxw(dev);
-       unsigned int          maxh   = norm_maxh(dev);
+       unsigned int          maxw = norm_maxw(dev);
+       unsigned int          maxh = norm_maxh(dev);
 
        *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
        if (*hscale >= 0x4000)
@@ -726,11 +726,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if (dev->board.is_27xx) {
-               /* FIXME: This is the only supported fmt */
-               width  = 640;
-               height = 480;
-       } else if (dev->board.is_em2800) {
+       if (dev->board.is_em2800) {
                /* the em2800 can only scale down to 50% */
                height = height > (3 * maxh / 4) ? maxh : maxh / 2;
                width = width > (3 * maxw / 4) ? maxw : maxw / 2;
@@ -767,12 +763,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
 {
        struct em28xx_fmt     *fmt;
 
-       /* FIXME: This is the only supported fmt */
-       if (dev->board.is_27xx) {
-               width  = 640;
-               height = 480;
-       }
-
        fmt = format_by_fourcc(fourcc);
        if (!fmt)
                return -EINVAL;
index d90fef463764646697ffe9ff1a69eeca7976c2c5..45bd513f62dcb8ed42bd9e37c58956f204f1d23f 100644 (file)
@@ -358,10 +358,15 @@ struct em28xx_input {
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
 
 enum em28xx_decoder {
-       EM28XX_NODECODER,
+       EM28XX_NODECODER = 0,
        EM28XX_TVP5150,
        EM28XX_SAA711X,
+};
+
+enum em28xx_sensor {
+       EM28XX_NOSENSOR = 0,
        EM28XX_MT9V011,
+       EM28XX_MT9M001,
 };
 
 enum em28xx_adecoder {
@@ -390,7 +395,7 @@ struct em28xx_board {
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
        unsigned int has_snapshot_button:1;
-       unsigned int is_27xx:1;
+       unsigned int is_webcam:1;
        unsigned int valid:1;
 
        unsigned char xclk, i2c_speed;
@@ -474,6 +479,14 @@ struct em28xx {
        struct v4l2_device v4l2_dev;
        struct em28xx_board board;
 
+       /* Webcam specific fields */
+       enum em28xx_sensor em28xx_sensor;
+       int sensor_xres, sensor_yres;
+       int sensor_xtal;
+
+       /* Vinmode/Vinctl used at the driver */
+       int vinmode, vinctl;
+
        unsigned int stream_on:1;       /* Locks streams */
        unsigned int has_audio_class:1;
        unsigned int has_alsa_audio:1;
@@ -754,17 +767,23 @@ static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
 /*FIXME: maxw should be dependent of alt mode */
 static inline unsigned int norm_maxw(struct em28xx *dev)
 {
+       if (dev->board.is_webcam)
+               return dev->sensor_xres;
+
        if (dev->board.max_range_640_480)
                return 640;
-       else
-               return 720;
+
+       return 720;
 }
 
 static inline unsigned int norm_maxh(struct em28xx *dev)
 {
+       if (dev->board.is_webcam)
+               return dev->sensor_yres;
+
        if (dev->board.max_range_640_480)
                return 480;
-       else
-               return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+
+       return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
 }
 #endif
index 578dc4ffc9659454da44d548eb80dd5a0018e87b..34f46f2bc0402af5c375e05432233e8a8553da11 100644 (file)
@@ -102,6 +102,22 @@ config USB_GSPCA_PAC7311
          To compile this driver as a module, choose M here: the
          module will be called gspca_pac7311.
 
+config USB_GSPCA_SN9C20X
+       tristate "SN9C20X USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+        Say Y here if you want support for cameras based on the
+        sn9c20x chips (SN9C201 and SN9C202).
+
+        To compile this driver as a module, choose M here: the
+        module will be called gspca_sn9c20x.
+
+config USB_GSPCA_SN9C20X_EVDEV
+       bool "Enable evdev support"
+       depends on USB_GSPCA_SN9C20X
+       ---help---
+        Say Y here in order to enable evdev support for sn9c20x webcam button.
+
 config USB_GSPCA_SONIXB
        tristate "SONIX Bayer USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 8a6643e8eb96d796ebaf6a02bf73d8e7306a0e7f..f6d3b86e9ad566952840305362b61f5ca1781997 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
 obj-$(CONFIG_USB_GSPCA_OV534)    += gspca_ov534.o
 obj-$(CONFIG_USB_GSPCA_PAC207)   += gspca_pac207.o
 obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SN9C20X)  += gspca_sn9c20x.o
 obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
 obj-$(CONFIG_USB_GSPCA_SONIXJ)   += gspca_sonixj.o
 obj-$(CONFIG_USB_GSPCA_SPCA500)  += gspca_spca500.o
@@ -35,6 +36,7 @@ gspca_ov519-objs    := ov519.o
 gspca_ov534-objs    := ov534.o
 gspca_pac207-objs   := pac207.o
 gspca_pac7311-objs  := pac7311.o
+gspca_sn9c20x-objs  := sn9c20x.o
 gspca_sonixb-objs   := sonixb.o
 gspca_sonixj-objs   := sonixj.o
 gspca_spca500-objs  := spca500.o
index 219cfa6fb877e2e20353bd0b160ac8933c8bc266..8d48ea1742c2f7ac808c6b9033d7eba69366ffaa 100644 (file)
@@ -846,6 +846,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index 1e89600986c89bd3ce19e2bf8a2d3f78c1ccd097..b8561dfb6c8c7bc08880a9057239f6854c582a5f 100644 (file)
@@ -727,6 +727,74 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       int ret;
+       struct gspca_dev *gspca_dev = priv;
+
+       if (!gspca_dev->sd_desc->get_chip_ident)
+               return -EINVAL;
+
+       if (!gspca_dev->sd_desc->get_register)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = gspca_dev->sd_desc->get_register(gspca_dev, reg);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+
+       return ret;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       int ret;
+       struct gspca_dev *gspca_dev = priv;
+
+       if (!gspca_dev->sd_desc->get_chip_ident)
+               return -EINVAL;
+
+       if (!gspca_dev->sd_desc->set_register)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = gspca_dev->sd_desc->set_register(gspca_dev, reg);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+
+       return ret;
+}
+#endif
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+                       struct v4l2_dbg_chip_ident *chip)
+{
+       int ret;
+       struct gspca_dev *gspca_dev = priv;
+
+       if (!gspca_dev->sd_desc->get_chip_ident)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+
+       return ret;
+}
+
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                struct v4l2_fmtdesc *fmtdesc)
 {
@@ -1883,6 +1951,11 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_s_parm          = vidioc_s_parm,
        .vidioc_s_std           = vidioc_s_std,
        .vidioc_enum_framesizes = vidioc_enum_framesizes,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register      = vidioc_g_register,
+       .vidioc_s_register      = vidioc_s_register,
+#endif
+       .vidioc_g_chip_ident    = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
index bd1faff8864454a9aa163603570fb62c935eab64..46c4effdfcd5b03776f6798eaafb58aebe9a78fa 100644 (file)
@@ -69,6 +69,10 @@ typedef void (*cam_v_op) (struct gspca_dev *);
 typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
 typedef int (*cam_jpg_op) (struct gspca_dev *,
                                struct v4l2_jpegcompression *);
+typedef int (*cam_reg_op) (struct gspca_dev *,
+                               struct v4l2_dbg_register *);
+typedef int (*cam_ident_op) (struct gspca_dev *,
+                               struct v4l2_dbg_chip_ident *);
 typedef int (*cam_streamparm_op) (struct gspca_dev *,
                                  struct v4l2_streamparm *);
 typedef int (*cam_qmnu_op) (struct gspca_dev *,
@@ -105,6 +109,11 @@ struct sd_desc {
        cam_qmnu_op querymenu;
        cam_streamparm_op get_streamparm;
        cam_streamparm_op set_streamparm;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       cam_reg_op set_register;
+       cam_reg_op get_register;
+#endif
+       cam_ident_op get_chip_ident;
 };
 
 /* packet types when moving from iso buf to frame buf */
index 191bcd7189798351e5a171767c86fd5e7b8686b1..0163903d1c0fb4a5dbbe0ec0a0b5bd5fa1b11284 100644 (file)
@@ -474,9 +474,6 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
-       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
@@ -522,9 +519,6 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
-       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
index 75e8d14e4ac74d0e620eff590d8e32d9fe7e0fab..de769caf013dd2f0e8e4330329e6745840128670 100644 (file)
@@ -201,6 +201,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
new file mode 100644 (file)
index 0000000..fcfbbd3
--- /dev/null
@@ -0,0 +1,2434 @@
+/*
+ *     Sonix sn9c201 sn9c202 library
+ *     Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
+ *     Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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
+ */
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/usb/input.h>
+#include <linux/input.h>
+#endif
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#include <media/v4l2-chip-ident.h>
+
+MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
+               "microdia project <microdia@googlegroups.com>");
+MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define MODULE_NAME "sn9c20x"
+
+#define MODE_RAW       0x10
+#define MODE_JPEG      0x20
+#define MODE_SXGA      0x80
+
+#define SENSOR_OV9650  0
+#define SENSOR_OV9655  1
+#define SENSOR_SOI968  2
+#define SENSOR_OV7660  3
+#define SENSOR_OV7670  4
+#define SENSOR_MT9V011 5
+#define SENSOR_MT9V111 6
+#define SENSOR_MT9V112 7
+#define SENSOR_MT9M001 8
+#define SENSOR_MT9M111 9
+#define SENSOR_HV7131R 10
+#define SENSOR_MT9VPRB 20
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;
+
+#define MIN_AVG_LUM 80
+#define MAX_AVG_LUM 130
+       atomic_t avg_lum;
+       u8 old_step;
+       u8 older_step;
+       u8 exposure_step;
+
+       u8 brightness;
+       u8 contrast;
+       u8 saturation;
+       s16 hue;
+       u8 gamma;
+       u8 red;
+       u8 blue;
+
+       u8 hflip;
+       u8 vflip;
+       u8 gain;
+       u16 exposure;
+       u8 auto_exposure;
+
+       u8 i2c_addr;
+       u8 sensor;
+       u8 hstart;
+       u8 vstart;
+
+       u8 *jpeg_hdr;
+       u8 quality;
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+       struct input_dev *input_dev;
+       u8 input_gpio;
+       struct task_struct *input_task;
+#endif
+};
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+       {
+#define BRIGHTNESS_IDX 0
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+#define BRIGHTNESS_DEFAULT 0x7f
+               .default_value = BRIGHTNESS_DEFAULT,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+#define CONTRAST_IDX 1
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+#define CONTRAST_DEFAULT 0x7f
+               .default_value = CONTRAST_DEFAULT,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+       {
+#define SATURATION_IDX 2
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Saturation",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+#define SATURATION_DEFAULT 0x7f
+               .default_value = SATURATION_DEFAULT,
+           },
+           .set = sd_setsaturation,
+           .get = sd_getsaturation,
+       },
+       {
+#define HUE_IDX 3
+           {
+               .id      = V4L2_CID_HUE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Hue",
+               .minimum = -180,
+               .maximum = 180,
+               .step    = 1,
+#define HUE_DEFAULT 0
+               .default_value = HUE_DEFAULT,
+           },
+           .set = sd_sethue,
+           .get = sd_gethue,
+       },
+       {
+#define GAMMA_IDX 4
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+#define GAMMA_DEFAULT 0x10
+               .default_value = GAMMA_DEFAULT,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
+       {
+#define BLUE_IDX 5
+           {
+               .id      = V4L2_CID_BLUE_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Blue Balance",
+               .minimum = 0,
+               .maximum = 0x7f,
+               .step    = 1,
+#define BLUE_DEFAULT 0x28
+               .default_value = BLUE_DEFAULT,
+           },
+           .set = sd_setbluebalance,
+           .get = sd_getbluebalance,
+       },
+       {
+#define RED_IDX 6
+           {
+               .id      = V4L2_CID_RED_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Red Balance",
+               .minimum = 0,
+               .maximum = 0x7f,
+               .step    = 1,
+#define RED_DEFAULT 0x28
+               .default_value = RED_DEFAULT,
+           },
+           .set = sd_setredbalance,
+           .get = sd_getredbalance,
+       },
+       {
+#define HFLIP_IDX 7
+           {
+               .id      = V4L2_CID_HFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Horizontal Flip",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define HFLIP_DEFAULT 0
+               .default_value = HFLIP_DEFAULT,
+           },
+           .set = sd_sethflip,
+           .get = sd_gethflip,
+       },
+       {
+#define VFLIP_IDX 8
+           {
+               .id      = V4L2_CID_VFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Vertical Flip",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define VFLIP_DEFAULT 0
+               .default_value = VFLIP_DEFAULT,
+           },
+           .set = sd_setvflip,
+           .get = sd_getvflip,
+       },
+       {
+#define EXPOSURE_IDX 9
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+               .maximum = 0x1780,
+               .step    = 1,
+#define EXPOSURE_DEFAULT 0x33
+               .default_value = EXPOSURE_DEFAULT,
+           },
+           .set = sd_setexposure,
+           .get = sd_getexposure,
+       },
+       {
+#define GAIN_IDX 10
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 0,
+               .maximum = 28,
+               .step    = 1,
+#define GAIN_DEFAULT 0x00
+               .default_value = GAIN_DEFAULT,
+           },
+           .set = sd_setgain,
+           .get = sd_getgain,
+       },
+       {
+#define AUTOGAIN_IDX 11
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Exposure",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define AUTO_EXPOSURE_DEFAULT 1
+               .default_value = AUTO_EXPOSURE_DEFAULT,
+           },
+           .set = sd_setautoexposure,
+           .get = sd_getautoexposure,
+       },
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 240,
+               .sizeimage = 240 * 120,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0 | MODE_JPEG},
+       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0 | MODE_RAW},
+       {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 240,
+               .sizeimage = 240 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 480,
+               .sizeimage = 480 * 240 ,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1 | MODE_JPEG},
+       {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 ,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1 | MODE_RAW},
+       {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 480,
+               .sizeimage = 480 * 240 ,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 960,
+               .sizeimage = 960 * 480,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2 | MODE_JPEG},
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2 | MODE_RAW},
+       {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 960,
+               .sizeimage = 960 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2},
+};
+
+static const struct v4l2_pix_format sxga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 240,
+               .sizeimage = 240 * 120,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0 | MODE_JPEG},
+       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0 | MODE_RAW},
+       {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 240,
+               .sizeimage = 240 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 480,
+               .sizeimage = 480 * 240 ,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1 | MODE_JPEG},
+       {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 ,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1 | MODE_RAW},
+       {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 480,
+               .sizeimage = 480 * 240 ,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 960,
+               .sizeimage = 960 * 480,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2 | MODE_JPEG},
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2 | MODE_RAW},
+       {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+               .bytesperline = 960,
+               .sizeimage = 960 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2},
+       {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1280,
+               .sizeimage = (1280 * 1024) + 64,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 3 | MODE_RAW | MODE_SXGA},
+};
+
+static const int hsv_red_x[] = {
+       41,  44,  46,  48,  50,  52,  54,  56,
+       58,  60,  62,  64,  66,  68,  70,  72,
+       74,  76,  78,  80,  81,  83,  85,  87,
+       88,  90,  92,  93,  95,  97,  98, 100,
+       101, 102, 104, 105, 107, 108, 109, 110,
+       112, 113, 114, 115, 116, 117, 118, 119,
+       120, 121, 122, 123, 123, 124, 125, 125,
+       126, 127, 127, 128, 128, 129, 129, 129,
+       130, 130, 130, 130, 131, 131, 131, 131,
+       131, 131, 131, 131, 130, 130, 130, 130,
+       129, 129, 129, 128, 128, 127, 127, 126,
+       125, 125, 124, 123, 122, 122, 121, 120,
+       119, 118, 117, 116, 115, 114, 112, 111,
+       110, 109, 107, 106, 105, 103, 102, 101,
+       99,  98,  96,  94,  93,  91,  90,  88,
+       86,  84,  83,  81,  79,  77,  75,  74,
+       72,  70,  68,  66,  64,  62,  60,  58,
+       56,  54,  52,  49,  47,  45,  43,  41,
+       39,  36,  34,  32,  30,  28,  25,  23,
+       21,  19,  16,  14,  12,   9,   7,   5,
+       3,   0,  -1,  -3,  -6,  -8, -10, -12,
+       -15, -17, -19, -22, -24, -26, -28, -30,
+       -33, -35, -37, -39, -41, -44, -46, -48,
+       -50, -52, -54, -56, -58, -60, -62, -64,
+       -66, -68, -70, -72, -74, -76, -78, -80,
+       -81, -83, -85, -87, -88, -90, -92, -93,
+       -95, -97, -98, -100, -101, -102, -104, -105,
+       -107, -108, -109, -110, -112, -113, -114, -115,
+       -116, -117, -118, -119, -120, -121, -122, -123,
+       -123, -124, -125, -125, -126, -127, -127, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -128, -127, -127, -126, -125, -125, -124, -123,
+       -122, -122, -121, -120, -119, -118, -117, -116,
+       -115, -114, -112, -111, -110, -109, -107, -106,
+       -105, -103, -102, -101, -99, -98, -96, -94,
+       -93, -91, -90, -88, -86, -84, -83, -81,
+       -79, -77, -75, -74, -72, -70, -68, -66,
+       -64, -62, -60, -58, -56, -54, -52, -49,
+       -47, -45, -43, -41, -39, -36, -34, -32,
+       -30, -28, -25, -23, -21, -19, -16, -14,
+       -12,  -9,  -7,  -5,  -3,   0,   1,   3,
+       6,   8,  10,  12,  15,  17,  19,  22,
+       24,  26,  28,  30,  33,  35,  37,  39, 41
+};
+
+static const int hsv_red_y[] = {
+       82,  80,  78,  76,  74,  73,  71,  69,
+       67,  65,  63,  61,  58,  56,  54,  52,
+       50,  48,  46,  44,  41,  39,  37,  35,
+       32,  30,  28,  26,  23,  21,  19,  16,
+       14,  12,  10,   7,   5,   3,   0,  -1,
+       -3,  -6,  -8, -10, -13, -15, -17, -19,
+       -22, -24, -26, -29, -31, -33, -35, -38,
+       -40, -42, -44, -46, -48, -51, -53, -55,
+       -57, -59, -61, -63, -65, -67, -69, -71,
+       -73, -75, -77, -79, -81, -82, -84, -86,
+       -88, -89, -91, -93, -94, -96, -98, -99,
+       -101, -102, -104, -105, -106, -108, -109, -110,
+       -112, -113, -114, -115, -116, -117, -119, -120,
+       -120, -121, -122, -123, -124, -125, -126, -126,
+       -127, -128, -128, -128, -128, -128, -128, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -128, -128, -128, -128, -128, -128, -128, -128,
+       -127, -127, -126, -125, -125, -124, -123, -122,
+       -121, -120, -119, -118, -117, -116, -115, -114,
+       -113, -111, -110, -109, -107, -106, -105, -103,
+       -102, -100, -99, -97, -96, -94, -92, -91,
+       -89, -87, -85, -84, -82, -80, -78, -76,
+       -74, -73, -71, -69, -67, -65, -63, -61,
+       -58, -56, -54, -52, -50, -48, -46, -44,
+       -41, -39, -37, -35, -32, -30, -28, -26,
+       -23, -21, -19, -16, -14, -12, -10,  -7,
+       -5,  -3,   0,   1,   3,   6,   8,  10,
+       13,  15,  17,  19,  22,  24,  26,  29,
+       31,  33,  35,  38,  40,  42,  44,  46,
+       48,  51,  53,  55,  57,  59,  61,  63,
+       65,  67,  69,  71,  73,  75,  77,  79,
+       81,  82,  84,  86,  88,  89,  91,  93,
+       94,  96,  98,  99, 101, 102, 104, 105,
+       106, 108, 109, 110, 112, 113, 114, 115,
+       116, 117, 119, 120, 120, 121, 122, 123,
+       124, 125, 126, 126, 127, 128, 128, 129,
+       129, 130, 130, 131, 131, 131, 131, 132,
+       132, 132, 132, 132, 132, 132, 132, 132,
+       132, 132, 132, 131, 131, 131, 130, 130,
+       130, 129, 129, 128, 127, 127, 126, 125,
+       125, 124, 123, 122, 121, 120, 119, 118,
+       117, 116, 115, 114, 113, 111, 110, 109,
+       107, 106, 105, 103, 102, 100,  99,  97,
+       96, 94, 92, 91, 89, 87, 85, 84, 82
+};
+
+static const int hsv_green_x[] = {
+       -124, -124, -125, -125, -125, -125, -125, -125,
+       -125, -126, -126, -125, -125, -125, -125, -125,
+       -125, -124, -124, -124, -123, -123, -122, -122,
+       -121, -121, -120, -120, -119, -118, -117, -117,
+       -116, -115, -114, -113, -112, -111, -110, -109,
+       -108, -107, -105, -104, -103, -102, -100, -99,
+       -98, -96, -95, -93, -92, -91, -89, -87,
+       -86, -84, -83, -81, -79, -77, -76, -74,
+       -72, -70, -69, -67, -65, -63, -61, -59,
+       -57, -55, -53, -51, -49, -47, -45, -43,
+       -41, -39, -37, -35, -33, -30, -28, -26,
+       -24, -22, -20, -18, -15, -13, -11,  -9,
+       -7,  -4,  -2,   0,   1,   3,   6,   8,
+       10,  12,  14,  17,  19,  21,  23,  25,
+       27,  29,  32,  34,  36,  38,  40,  42,
+       44,  46,  48,  50,  52,  54,  56,  58,
+       60,  62,  64,  66,  68,  70,  71,  73,
+       75,  77,  78,  80,  82,  83,  85,  87,
+       88,  90,  91,  93,  94,  96,  97,  98,
+       100, 101, 102, 104, 105, 106, 107, 108,
+       109, 111, 112, 113, 113, 114, 115, 116,
+       117, 118, 118, 119, 120, 120, 121, 122,
+       122, 123, 123, 124, 124, 124, 125, 125,
+       125, 125, 125, 125, 125, 126, 126, 125,
+       125, 125, 125, 125, 125, 124, 124, 124,
+       123, 123, 122, 122, 121, 121, 120, 120,
+       119, 118, 117, 117, 116, 115, 114, 113,
+       112, 111, 110, 109, 108, 107, 105, 104,
+       103, 102, 100,  99,  98,  96,  95,  93,
+       92,  91,  89,  87,  86,  84,  83,  81,
+       79,  77,  76,  74,  72,  70,  69,  67,
+       65,  63,  61,  59,  57,  55,  53,  51,
+       49,  47,  45,  43,  41,  39,  37,  35,
+       33,  30,  28,  26,  24,  22,  20,  18,
+       15,  13,  11,   9,   7,   4,   2,   0,
+       -1,  -3,  -6,  -8, -10, -12, -14, -17,
+       -19, -21, -23, -25, -27, -29, -32, -34,
+       -36, -38, -40, -42, -44, -46, -48, -50,
+       -52, -54, -56, -58, -60, -62, -64, -66,
+       -68, -70, -71, -73, -75, -77, -78, -80,
+       -82, -83, -85, -87, -88, -90, -91, -93,
+       -94, -96, -97, -98, -100, -101, -102, -104,
+       -105, -106, -107, -108, -109, -111, -112, -113,
+       -113, -114, -115, -116, -117, -118, -118, -119,
+       -120, -120, -121, -122, -122, -123, -123, -124, -124
+};
+
+static const int hsv_green_y[] = {
+       -100, -99, -98, -97, -95, -94, -93, -91,
+       -90, -89, -87, -86, -84, -83, -81, -80,
+       -78, -76, -75, -73, -71, -70, -68, -66,
+       -64, -63, -61, -59, -57, -55, -53, -51,
+       -49, -48, -46, -44, -42, -40, -38, -36,
+       -34, -32, -30, -27, -25, -23, -21, -19,
+       -17, -15, -13, -11,  -9,  -7,  -4,  -2,
+       0,   1,   3,   5,   7,   9,  11,  14,
+       16,  18,  20,  22,  24,  26,  28,  30,
+       32,  34,  36,  38,  40,  42,  44,  46,
+       48,  50,  52,  54,  56,  58,  59,  61,
+       63,  65,  67,  68,  70,  72,  74,  75,
+       77,  78,  80,  82,  83,  85,  86,  88,
+       89,  90,  92,  93,  95,  96,  97,  98,
+       100, 101, 102, 103, 104, 105, 106, 107,
+       108, 109, 110, 111, 112, 112, 113, 114,
+       115, 115, 116, 116, 117, 117, 118, 118,
+       119, 119, 119, 120, 120, 120, 120, 120,
+       121, 121, 121, 121, 121, 121, 120, 120,
+       120, 120, 120, 119, 119, 119, 118, 118,
+       117, 117, 116, 116, 115, 114, 114, 113,
+       112, 111, 111, 110, 109, 108, 107, 106,
+       105, 104, 103, 102, 100,  99,  98,  97,
+       95,  94,  93,  91,  90,  89,  87,  86,
+       84,  83,  81,  80,  78,  76,  75,  73,
+       71,  70,  68,  66,  64,  63,  61,  59,
+       57,  55,  53,  51,  49,  48,  46,  44,
+       42,  40,  38,  36,  34,  32,  30,  27,
+       25,  23,  21,  19,  17,  15,  13,  11,
+       9,   7,   4,   2,   0,  -1,  -3,  -5,
+       -7,  -9, -11, -14, -16, -18, -20, -22,
+       -24, -26, -28, -30, -32, -34, -36, -38,
+       -40, -42, -44, -46, -48, -50, -52, -54,
+       -56, -58, -59, -61, -63, -65, -67, -68,
+       -70, -72, -74, -75, -77, -78, -80, -82,
+       -83, -85, -86, -88, -89, -90, -92, -93,
+       -95, -96, -97, -98, -100, -101, -102, -103,
+       -104, -105, -106, -107, -108, -109, -110, -111,
+       -112, -112, -113, -114, -115, -115, -116, -116,
+       -117, -117, -118, -118, -119, -119, -119, -120,
+       -120, -120, -120, -120, -121, -121, -121, -121,
+       -121, -121, -120, -120, -120, -120, -120, -119,
+       -119, -119, -118, -118, -117, -117, -116, -116,
+       -115, -114, -114, -113, -112, -111, -111, -110,
+       -109, -108, -107, -106, -105, -104, -103, -102, -100
+};
+
+static const int hsv_blue_x[] = {
+       112, 113, 114, 114, 115, 116, 117, 117,
+       118, 118, 119, 119, 120, 120, 120, 121,
+       121, 121, 122, 122, 122, 122, 122, 122,
+       122, 122, 122, 122, 122, 122, 121, 121,
+       121, 120, 120, 120, 119, 119, 118, 118,
+       117, 116, 116, 115, 114, 113, 113, 112,
+       111, 110, 109, 108, 107, 106, 105, 104,
+       103, 102, 100,  99,  98,  97,  95,  94,
+       93,  91,  90,  88,  87,  85,  84,  82,
+       80,  79,  77,  76,  74,  72,  70,  69,
+       67,  65,  63,  61,  60,  58,  56,  54,
+       52,  50,  48,  46,  44,  42,  40,  38,
+       36,  34,  32,  30,  28,  26,  24,  22,
+       19,  17,  15,  13,  11,   9,   7,   5,
+       2,   0,  -1,  -3,  -5,  -7,  -9, -12,
+       -14, -16, -18, -20, -22, -24, -26, -28,
+       -31, -33, -35, -37, -39, -41, -43, -45,
+       -47, -49, -51, -53, -54, -56, -58, -60,
+       -62, -64, -66, -67, -69, -71, -73, -74,
+       -76, -78, -79, -81, -83, -84, -86, -87,
+       -89, -90, -92, -93, -94, -96, -97, -98,
+       -99, -101, -102, -103, -104, -105, -106, -107,
+       -108, -109, -110, -111, -112, -113, -114, -114,
+       -115, -116, -117, -117, -118, -118, -119, -119,
+       -120, -120, -120, -121, -121, -121, -122, -122,
+       -122, -122, -122, -122, -122, -122, -122, -122,
+       -122, -122, -121, -121, -121, -120, -120, -120,
+       -119, -119, -118, -118, -117, -116, -116, -115,
+       -114, -113, -113, -112, -111, -110, -109, -108,
+       -107, -106, -105, -104, -103, -102, -100, -99,
+       -98, -97, -95, -94, -93, -91, -90, -88,
+       -87, -85, -84, -82, -80, -79, -77, -76,
+       -74, -72, -70, -69, -67, -65, -63, -61,
+       -60, -58, -56, -54, -52, -50, -48, -46,
+       -44, -42, -40, -38, -36, -34, -32, -30,
+       -28, -26, -24, -22, -19, -17, -15, -13,
+       -11,  -9,  -7,  -5,  -2,   0,   1,   3,
+       5,   7,   9,  12,  14,  16,  18,  20,
+       22,  24,  26,  28,  31,  33,  35,  37,
+       39,  41,  43,  45,  47,  49,  51,  53,
+       54,  56,  58,  60,  62,  64,  66,  67,
+       69,  71,  73,  74,  76,  78,  79,  81,
+       83,  84,  86,  87,  89,  90,  92,  93,
+       94,  96,  97,  98,  99, 101, 102, 103,
+       104, 105, 106, 107, 108, 109, 110, 111, 112
+};
+
+static const int hsv_blue_y[] = {
+       -11, -13, -15, -17, -19, -21, -23, -25,
+       -27, -29, -31, -33, -35, -37, -39, -41,
+       -43, -45, -46, -48, -50, -52, -54, -55,
+       -57, -59, -61, -62, -64, -66, -67, -69,
+       -71, -72, -74, -75, -77, -78, -80, -81,
+       -83, -84, -86, -87, -88, -90, -91, -92,
+       -93, -95, -96, -97, -98, -99, -100, -101,
+       -102, -103, -104, -105, -106, -106, -107, -108,
+       -109, -109, -110, -111, -111, -112, -112, -113,
+       -113, -114, -114, -114, -115, -115, -115, -115,
+       -116, -116, -116, -116, -116, -116, -116, -116,
+       -116, -115, -115, -115, -115, -114, -114, -114,
+       -113, -113, -112, -112, -111, -111, -110, -110,
+       -109, -108, -108, -107, -106, -105, -104, -103,
+       -102, -101, -100, -99, -98, -97, -96, -95,
+       -94, -93, -91, -90, -89, -88, -86, -85,
+       -84, -82, -81, -79, -78, -76, -75, -73,
+       -71, -70, -68, -67, -65, -63, -62, -60,
+       -58, -56, -55, -53, -51, -49, -47, -45,
+       -44, -42, -40, -38, -36, -34, -32, -30,
+       -28, -26, -24, -22, -20, -18, -16, -14,
+       -12, -10,  -8,  -6,  -4,  -2,   0,   1,
+       3,   5,   7,   9,  11,  13,  15,  17,
+       19,  21,  23,  25,  27,  29,  31,  33,
+       35,  37,  39,  41,  43,  45,  46,  48,
+       50,  52,  54,  55,  57,  59,  61,  62,
+       64,  66,  67,  69,  71,  72,  74,  75,
+       77,  78,  80,  81,  83,  84,  86,  87,
+       88,  90,  91,  92,  93,  95,  96,  97,
+       98,  99, 100, 101, 102, 103, 104, 105,
+       106, 106, 107, 108, 109, 109, 110, 111,
+       111, 112, 112, 113, 113, 114, 114, 114,
+       115, 115, 115, 115, 116, 116, 116, 116,
+       116, 116, 116, 116, 116, 115, 115, 115,
+       115, 114, 114, 114, 113, 113, 112, 112,
+       111, 111, 110, 110, 109, 108, 108, 107,
+       106, 105, 104, 103, 102, 101, 100,  99,
+       98,  97,  96,  95,  94,  93,  91,  90,
+       89,  88,  86,  85,  84,  82,  81,  79,
+       78,  76,  75,  73,  71,  70,  68,  67,
+       65,  63,  62,  60,  58,  56,  55,  53,
+       51,  49,  47,  45,  44,  42,  40,  38,
+       36,  34,  32,  30,  28,  26,  24,  22,
+       20,  18,  16,  14,  12,  10,   8,   6,
+       4,   2,   0,  -1,  -3,  -5,  -7,  -9, -11
+};
+
+static u16 i2c_ident[] = {
+       V4L2_IDENT_OV9650,
+       V4L2_IDENT_OV9655,
+       V4L2_IDENT_SOI968,
+       V4L2_IDENT_OV7660,
+       V4L2_IDENT_OV7670,
+       V4L2_IDENT_MT9V011,
+       V4L2_IDENT_MT9V111,
+       V4L2_IDENT_MT9V112,
+       V4L2_IDENT_MT9M001C12ST,
+       V4L2_IDENT_MT9M111,
+       V4L2_IDENT_HV7131R,
+};
+
+static u16 bridge_init[][2] = {
+       {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
+       {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
+       {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
+       {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
+       {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
+       {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
+       {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
+       {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
+       {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
+       {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
+       {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
+       {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
+       {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
+       {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
+       {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
+       {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
+       {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
+       {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
+       {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80}
+};
+
+/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
+static u8 ov_gain[] = {
+       0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
+       0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
+       0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
+       0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
+       0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
+       0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
+       0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
+       0x70 /* 8x */
+};
+
+/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
+static u16 micron1_gain[] = {
+       /* 1x   1.25x   1.5x    1.75x */
+       0x0020, 0x0028, 0x0030, 0x0038,
+       /* 2x   2.25x   2.5x    2.75x */
+       0x00a0, 0x00a4, 0x00a8, 0x00ac,
+       /* 3x   3.25x   3.5x    3.75x */
+       0x00b0, 0x00b4, 0x00b8, 0x00bc,
+       /* 4x   4.25x   4.5x    4.75x */
+       0x00c0, 0x00c4, 0x00c8, 0x00cc,
+       /* 5x   5.25x   5.5x    5.75x */
+       0x00d0, 0x00d4, 0x00d8, 0x00dc,
+       /* 6x   6.25x   6.5x    6.75x */
+       0x00e0, 0x00e4, 0x00e8, 0x00ec,
+       /* 7x   7.25x   7.5x    7.75x */
+       0x00f0, 0x00f4, 0x00f8, 0x00fc,
+       /* 8x */
+       0x01c0
+};
+
+/* mt9m001 sensor uses a different gain formula then other micron sensors */
+/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
+static u16 micron2_gain[] = {
+       /* 1x   1.25x   1.5x    1.75x */
+       0x0008, 0x000a, 0x000c, 0x000e,
+       /* 2x   2.25x   2.5x    2.75x */
+       0x0010, 0x0012, 0x0014, 0x0016,
+       /* 3x   3.25x   3.5x    3.75x */
+       0x0018, 0x001a, 0x001c, 0x001e,
+       /* 4x   4.25x   4.5x    4.75x */
+       0x0020, 0x0051, 0x0052, 0x0053,
+       /* 5x   5.25x   5.5x    5.75x */
+       0x0054, 0x0055, 0x0056, 0x0057,
+       /* 6x   6.25x   6.5x    6.75x */
+       0x0058, 0x0059, 0x005a, 0x005b,
+       /* 7x   7.25x   7.5x    7.75x */
+       0x005c, 0x005d, 0x005e, 0x005f,
+       /* 8x */
+       0x0060
+};
+
+/* Gain = .5 + bit[7:0] / 16 */
+static u8 hv7131r_gain[] = {
+       0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
+       0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
+       0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
+       0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
+       0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
+       0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
+       0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
+       0x78 /* 8x */
+};
+
+static u8 soi968_init[][2] = {
+       {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+       {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
+       {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
+       {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
+       {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
+       {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
+       {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13},
+       {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
+       {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
+       {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
+       {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
+};
+
+static u8 ov7660_init[][2] = {
+       {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
+       {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
+       {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
+       {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
+       {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
+       {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
+};
+
+static u8 ov7670_init[][2] = {
+       {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+       {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
+       {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
+       {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
+       {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
+       {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
+       {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
+       {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
+       {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
+       {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
+       {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
+       {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
+       {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
+       {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
+       {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
+       {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
+       {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
+       {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
+       {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
+       {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
+       {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
+       {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
+       {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
+       {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
+       {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
+       {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
+       {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
+       {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
+       {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
+       {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
+       {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
+       {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
+       {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
+       {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
+       {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
+       {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
+       {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
+       {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
+       {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
+       {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
+       {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
+       {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
+       {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
+       {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
+       {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
+       {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
+       {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
+       {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
+       {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
+       {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
+       {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
+       {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
+       {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
+       {0x93, 0x00},
+};
+
+static u8 ov9650_init[][2] = {
+       {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+       {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
+       {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
+       {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
+       {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
+       {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
+       {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
+       {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
+       {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
+       {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
+       {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
+       {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
+       {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
+       {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
+       {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
+       {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
+       {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
+       {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
+       {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
+       {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
+       {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
+       {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
+       {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
+       {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
+       {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
+       {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
+       {0xaa, 0x92}, {0xab, 0x0a},
+};
+
+static u8 ov9655_init[][2] = {
+       {0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
+       {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
+       {0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
+       {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x32, 0xbf},
+       {0x34, 0x3d}, {0x35, 0x00}, {0x36, 0xf8}, {0x38, 0x12},
+       {0x39, 0x57}, {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c},
+       {0x3d, 0x19}, {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40},
+       {0x42, 0x80}, {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a},
+       {0x48, 0x3c}, {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc},
+       {0x4d, 0xdc}, {0x4e, 0xdc}, {0x69, 0x02}, {0x6c, 0x04},
+       {0x6f, 0x9e}, {0x70, 0x05}, {0x71, 0x78}, {0x77, 0x02},
+       {0x8a, 0x23}, {0x8c, 0x0d}, {0x90, 0x7e}, {0x91, 0x7c},
+       {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, {0xa6, 0x60},
+       {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, {0xab, 0x04},
+       {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80},
+       {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, {0xb6, 0xaf},
+       {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, {0xbe, 0x3b},
+       {0xbf, 0x3a}, {0xc0, 0xe2}, {0xc1, 0xc8}, {0xc2, 0x01},
+       {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
+       {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x12, 0x61},
+       {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
+       {0x03, 0x12}, {0x17, 0x14}, {0x18, 0x00}, {0x19, 0x01},
+       {0x1a, 0x3d}, {0x32, 0xbf}, {0x11, 0x80}, {0x2a, 0x10},
+       {0x2b, 0x0a}, {0x92, 0x00}, {0x93, 0x00}, {0x1e, 0x04},
+       {0x1e, 0x04}, {0x10, 0x7c}, {0x04, 0x03}, {0xa1, 0x00},
+       {0x2d, 0x00}, {0x2e, 0x00}, {0x00, 0x00}, {0x01, 0x80},
+       {0x02, 0x80}, {0x12, 0x61}, {0x36, 0xfa}, {0x8c, 0x8d},
+       {0xc0, 0xaa}, {0x69, 0x0a}, {0x03, 0x12}, {0x17, 0x14},
+       {0x18, 0x00}, {0x19, 0x01}, {0x1a, 0x3d}, {0x32, 0xbf},
+       {0x11, 0x80}, {0x2a, 0x10}, {0x2b, 0x0a}, {0x92, 0x00},
+       {0x93, 0x00}, {0x04, 0x01}, {0x10, 0x1f}, {0xa1, 0x00},
+       {0x00, 0x0a}, {0xa1, 0x00}, {0x10, 0x5d}, {0x04, 0x03},
+       {0x00, 0x01}, {0xa1, 0x00}, {0x10, 0x7c}, {0x04, 0x03},
+       {0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
+};
+
+static u16 mt9v112_init[][2] = {
+       {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
+       {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
+       {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
+       {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
+       {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
+       {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
+       {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
+       {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
+       {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
+       {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
+       {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
+       {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
+       {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
+       {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
+       {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
+       {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
+};
+
+static u16 mt9v111_init[][2] = {
+       {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
+       {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
+       {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
+       {0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03},
+       {0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c},
+       {0x2d, 0xf0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064},
+       {0x67, 0x4010}, {0x06, 0x301e}, {0x08, 0x0480},
+       {0x01, 0x0004}, {0x02, 0x0016}, {0x03, 0x01e6},
+       {0x04, 0x0286}, {0x05, 0x0004}, {0x06, 0x0000},
+       {0x07, 0x3002}, {0x08, 0x0008}, {0x0c, 0x0000},
+       {0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000},
+       {0x10, 0x0000}, {0x11, 0x0000}, {0x12, 0x00b0},
+       {0x13, 0x007c}, {0x14, 0x0000}, {0x15, 0x0000},
+       {0x16, 0x0000}, {0x17, 0x0000}, {0x18, 0x0000},
+       {0x19, 0x0000}, {0x1a, 0x0000}, {0x1b, 0x0000},
+       {0x1c, 0x0000}, {0x1d, 0x0000}, {0x30, 0x0000},
+       {0x30, 0x0005}, {0x31, 0x0000}, {0x02, 0x0016},
+       {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0004},
+       {0x06, 0x0000}, {0x07, 0x3002}, {0x06, 0x002d},
+       {0x05, 0x0004}, {0x09, 0x0064}, {0x2b, 0x00a0},
+       {0x2c, 0x00a0}, {0x2d, 0x00a0}, {0x2e, 0x00a0},
+       {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281},
+       {0x05, 0x0004}, {0x06, 0x002d}, {0x07, 0x3002},
+       {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
+};
+
+static u16 mt9v011_init[][2] = {
+       {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
+       {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
+       {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
+       {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
+       {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
+       {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
+       {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
+       {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
+       {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
+       {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
+       {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
+       {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
+       {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
+       {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
+       {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
+       {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
+       {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
+       {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
+       {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
+       {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
+       {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
+       {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
+       {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
+       {0x06, 0x0029}, {0x05, 0x0009},
+};
+
+static u16 mt9m001_init[][2] = {
+       {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
+       {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
+       {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
+       {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
+       {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
+       {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
+       {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
+       {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
+       {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
+       {0x2e, 0x0029}, {0x07, 0x0002},
+};
+
+static u16 mt9m111_init[][2] = {
+       {0xf0, 0x0000}, {0x0d, 0x0008}, {0x0d, 0x0009},
+       {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300},
+       {0x9b, 0x4300}, {0xa1, 0x0280}, {0xa4, 0x0200},
+       {0x06, 0x308e}, {0xf0, 0x0000},
+};
+
+static u8 hv7131r_init[][2] = {
+       {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
+       {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
+       {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
+       {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
+       {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
+       {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
+       {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
+       {0x23, 0x09}, {0x01, 0x08},
+};
+
+int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int result;
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0x00,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       reg,
+                       0x00,
+                       gspca_dev->usb_buf,
+                       length,
+                       500);
+       if (unlikely(result < 0 || result != length)) {
+               err("Read register failed 0x%02X", reg);
+               return -EIO;
+       }
+       return 0;
+}
+
+int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int result;
+       memcpy(gspca_dev->usb_buf, buffer, length);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       0x08,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       reg,
+                       0x00,
+                       gspca_dev->usb_buf,
+                       length,
+                       500);
+       if (unlikely(result < 0 || result != length)) {
+               err("Write register failed index 0x%02X", reg);
+               return -EIO;
+       }
+       return 0;
+}
+
+int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+{
+       u8 data[1] = {value};
+       return reg_w(gspca_dev, reg, data, 1);
+}
+
+int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+{
+       int i;
+       reg_w(gspca_dev, 0x10c0, buffer, 8);
+       for (i = 0; i < 5; i++) {
+               reg_r(gspca_dev, 0x10c0, 1);
+               if (gspca_dev->usb_buf[0] & 0x04) {
+                       if (gspca_dev->usb_buf[0] & 0x08)
+                               return -1;
+                       return 0;
+               }
+               msleep(1);
+       }
+       return -1;
+}
+
+int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       u8 row[8];
+
+       /*
+        * from the point of view of the bridge, the length
+        * includes the address
+        */
+       row[0] = 0x81 | (2 << 4);
+       row[1] = sd->i2c_addr;
+       row[2] = reg;
+       row[3] = val;
+       row[4] = 0x00;
+       row[5] = 0x00;
+       row[6] = 0x00;
+       row[7] = 0x10;
+
+       return i2c_w(gspca_dev, row);
+}
+
+int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 row[8];
+
+       /*
+        * from the point of view of the bridge, the length
+        * includes the address
+        */
+       row[0] = 0x81 | (3 << 4);
+       row[1] = sd->i2c_addr;
+       row[2] = reg;
+       row[3] = (val >> 8) & 0xff;
+       row[4] = val & 0xff;
+       row[5] = 0x00;
+       row[6] = 0x00;
+       row[7] = 0x10;
+
+       return i2c_w(gspca_dev, row);
+}
+
+int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 row[8];
+
+       row[0] = 0x81 | 0x10;
+       row[1] = sd->i2c_addr;
+       row[2] = reg;
+       row[3] = 0;
+       row[4] = 0;
+       row[5] = 0;
+       row[6] = 0;
+       row[7] = 0x10;
+       reg_w(gspca_dev, 0x10c0, row, 8);
+       msleep(1);
+       row[0] = 0x81 | (2 << 4) | 0x02;
+       row[2] = 0;
+       reg_w(gspca_dev, 0x10c0, row, 8);
+       msleep(1);
+       reg_r(gspca_dev, 0x10c2, 5);
+       *val = gspca_dev->usb_buf[3];
+       return 0;
+}
+
+int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 row[8];
+
+       row[0] = 0x81 | 0x10;
+       row[1] = sd->i2c_addr;
+       row[2] = reg;
+       row[3] = 0;
+       row[4] = 0;
+       row[5] = 0;
+       row[6] = 0;
+       row[7] = 0x10;
+       reg_w(gspca_dev, 0x10c0, row, 8);
+       msleep(1);
+       row[0] = 0x81 | (3 << 4) | 0x02;
+       row[2] = 0;
+       reg_w(gspca_dev, 0x10c0, row, 8);
+       msleep(1);
+       reg_r(gspca_dev, 0x10c2, 5);
+       *val = (gspca_dev->usb_buf[2] << 8) | gspca_dev->usb_buf[3];
+       return 0;
+}
+
+static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
+               if (i2c_w1(gspca_dev, ov9650_init[i][0],
+                               ov9650_init[i][1]) < 0) {
+                       err("OV9650 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       sd->hstart = 1;
+       sd->vstart = 7;
+       return 0;
+}
+
+static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
+               if (i2c_w1(gspca_dev, ov9655_init[i][0],
+                               ov9655_init[i][1]) < 0) {
+                       err("OV9655 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       /* disable hflip and vflip */
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       sd->hstart = 0;
+       sd->vstart = 7;
+       return 0;
+}
+
+static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
+               if (i2c_w1(gspca_dev, soi968_init[i][0],
+                               soi968_init[i][1]) < 0) {
+                       err("SOI968 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       /* disable hflip and vflip */
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       sd->hstart = 60;
+       sd->vstart = 11;
+       return 0;
+}
+
+static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
+               if (i2c_w1(gspca_dev, ov7660_init[i][0],
+                               ov7660_init[i][1]) < 0) {
+                       err("OV7660 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       /* disable hflip and vflip */
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       sd->hstart = 1;
+       sd->vstart = 1;
+       return 0;
+}
+
+static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
+               if (i2c_w1(gspca_dev, ov7670_init[i][0],
+                               ov7670_init[i][1]) < 0) {
+                       err("OV7670 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       /* disable hflip and vflip */
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       sd->hstart = 0;
+       sd->vstart = 1;
+       return 0;
+}
+
+static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       u16 value;
+       int ret;
+
+       sd->i2c_addr = 0x5d;
+       ret = i2c_r2(gspca_dev, 0xff, &value);
+       if ((ret == 0) && (value == 0x8243)) {
+               for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
+                       if (i2c_w2(gspca_dev, mt9v011_init[i][0],
+                                       mt9v011_init[i][1]) < 0) {
+                               err("MT9V011 sensor initialization failed");
+                               return -ENODEV;
+                       }
+               }
+               sd->hstart = 2;
+               sd->vstart = 2;
+               sd->sensor = SENSOR_MT9V011;
+               info("MT9V011 sensor detected");
+               return 0;
+       }
+
+       sd->i2c_addr = 0x5c;
+       i2c_w2(gspca_dev, 0x01, 0x0004);
+       ret = i2c_r2(gspca_dev, 0xff, &value);
+       if ((ret == 0) && (value == 0x823a)) {
+               for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
+                       if (i2c_w2(gspca_dev, mt9v111_init[i][0],
+                                       mt9v111_init[i][1]) < 0) {
+                               err("MT9V111 sensor initialization failed");
+                               return -ENODEV;
+                       }
+               }
+               sd->hstart = 2;
+               sd->vstart = 2;
+               sd->sensor = SENSOR_MT9V111;
+               info("MT9V111 sensor detected");
+               return 0;
+       }
+
+       sd->i2c_addr = 0x5d;
+       ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
+       if (ret < 0) {
+               sd->i2c_addr = 0x48;
+               i2c_w2(gspca_dev, 0xf0, 0x0000);
+       }
+       ret = i2c_r2(gspca_dev, 0x00, &value);
+       if ((ret == 0) && (value == 0x1229)) {
+               for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
+                       if (i2c_w2(gspca_dev, mt9v112_init[i][0],
+                                       mt9v112_init[i][1]) < 0) {
+                               err("MT9V112 sensor initialization failed");
+                               return -ENODEV;
+                       }
+               }
+               sd->hstart = 6;
+               sd->vstart = 2;
+               sd->sensor = SENSOR_MT9V112;
+               info("MT9V112 sensor detected");
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
+               if (i2c_w2(gspca_dev, mt9m111_init[i][0],
+                               mt9m111_init[i][1]) < 0) {
+                       err("MT9M111 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       sd->hstart = 0;
+       sd->vstart = 2;
+       return 0;
+}
+
+static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
+               if (i2c_w2(gspca_dev, mt9m001_init[i][0],
+                               mt9m001_init[i][1]) < 0) {
+                       err("MT9M001 sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       /* disable hflip and vflip */
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       sd->hstart = 2;
+       sd->vstart = 2;
+       return 0;
+}
+
+static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+{
+       int i;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
+               if (i2c_w1(gspca_dev, hv7131r_init[i][0],
+                               hv7131r_init[i][1]) < 0) {
+                       err("HV7131R Sensor initialization failed");
+                       return -ENODEV;
+               }
+       }
+       sd->hstart = 0;
+       sd->vstart = 1;
+       return 0;
+}
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+static int input_kthread(void *data)
+{
+       struct gspca_dev *gspca_dev = (struct gspca_dev *)data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       DECLARE_WAIT_QUEUE_HEAD(wait);
+       set_freezable();
+       for (;;) {
+               if (kthread_should_stop())
+                       break;
+
+               if (reg_r(gspca_dev, 0x1005, 1) < 0)
+                       continue;
+
+               input_report_key(sd->input_dev,
+                                KEY_CAMERA,
+                                gspca_dev->usb_buf[0] & sd->input_gpio);
+               input_sync(sd->input_dev);
+
+               wait_event_freezable_timeout(wait,
+                                            kthread_should_stop(),
+                                            msecs_to_jiffies(100));
+       }
+       return 0;
+}
+
+
+static int sn9c20x_input_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       if (sd->input_gpio == 0)
+               return 0;
+
+       sd->input_dev = input_allocate_device();
+       if (!sd->input_dev)
+               return -ENOMEM;
+
+       sd->input_dev->name = "SN9C20X Webcam";
+
+       sd->input_dev->phys = kasprintf(GFP_KERNEL, "usb-%s-%s",
+                                        gspca_dev->dev->bus->bus_name,
+                                        gspca_dev->dev->devpath);
+
+       if (!sd->input_dev->phys)
+               return -ENOMEM;
+
+       usb_to_input_id(gspca_dev->dev, &sd->input_dev->id);
+       sd->input_dev->dev.parent = &gspca_dev->dev->dev;
+
+       set_bit(EV_KEY, sd->input_dev->evbit);
+       set_bit(KEY_CAMERA, sd->input_dev->keybit);
+
+       if (input_register_device(sd->input_dev))
+               return -EINVAL;
+
+       sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%d",
+                                    gspca_dev->vdev.minor);
+
+       if (IS_ERR(sd->input_task))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void sn9c20x_input_cleanup(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       if (sd->input_task != NULL && !IS_ERR(sd->input_task))
+               kthread_stop(sd->input_task);
+
+       if (sd->input_dev != NULL) {
+               input_unregister_device(sd->input_dev);
+               kfree(sd->input_dev->phys);
+               input_free_device(sd->input_dev);
+               sd->input_dev = NULL;
+       }
+}
+#endif
+
+static int set_cmatrix(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 hue_coord, hue_index = 180 + sd->hue;
+       u8 cmatrix[21];
+       memset(cmatrix, 0, 21);
+
+       cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+       cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
+       cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
+       cmatrix[18] = sd->brightness - 0x80;
+
+       hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+       cmatrix[6] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[7] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+       cmatrix[8] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[9] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+       cmatrix[10] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[11] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+       cmatrix[12] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[13] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+       cmatrix[14] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[15] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+       cmatrix[16] = (unsigned char)(hue_coord & 0xff);
+       cmatrix[17] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+       return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+}
+
+static int set_gamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 gamma[17];
+       u8 gval = sd->gamma * 0xb8 / 0x100;
+
+
+       gamma[0] = 0x0a;
+       gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
+       gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
+       gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
+       gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
+       gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
+       gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
+       gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
+       gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
+       gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
+       gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
+       gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
+       gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
+       gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
+       gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
+       gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
+       gamma[16] = 0xf5;
+
+       return reg_w(gspca_dev, 0x1190, gamma, 17);
+}
+
+static int set_redblue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       reg_w1(gspca_dev, 0x118c, sd->red);
+       reg_w1(gspca_dev, 0x118f, sd->blue);
+       return 0;
+}
+
+static int set_hvflip(struct gspca_dev *gspca_dev)
+{
+       u8 value, tslb;
+       u16 value2;
+       struct sd *sd = (struct sd *) gspca_dev;
+       switch (sd->sensor) {
+       case SENSOR_OV9650:
+               i2c_r1(gspca_dev, 0x1e, &value);
+               value &= ~0x30;
+               tslb = 0x01;
+               if (sd->hflip)
+                       value |= 0x20;
+               if (sd->vflip) {
+                       value |= 0x10;
+                       tslb = 0x49;
+               }
+               i2c_w1(gspca_dev, 0x1e, value);
+               i2c_w1(gspca_dev, 0x3a, tslb);
+               break;
+       case SENSOR_MT9V111:
+       case SENSOR_MT9V011:
+               i2c_r2(gspca_dev, 0x20, &value2);
+               value2 &= ~0xc0a0;
+               if (sd->hflip)
+                       value2 |= 0x8080;
+               if (sd->vflip)
+                       value2 |= 0x4020;
+               i2c_w2(gspca_dev, 0x20, value2);
+               break;
+       case SENSOR_MT9M111:
+       case SENSOR_MT9V112:
+               i2c_r2(gspca_dev, 0x20, &value2);
+               value2 &= ~0x0003;
+               if (sd->hflip)
+                       value2 |= 0x0002;
+               if (sd->vflip)
+                       value2 |= 0x0001;
+               i2c_w2(gspca_dev, 0x20, value2);
+               break;
+       case SENSOR_HV7131R:
+               i2c_r1(gspca_dev, 0x01, &value);
+               value &= ~0x03;
+               if (sd->vflip)
+                       value |= 0x01;
+               if (sd->hflip)
+                       value |= 0x02;
+               i2c_w1(gspca_dev, 0x01, value);
+               break;
+       }
+       return 0;
+}
+
+static int set_exposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+       case SENSOR_OV7670:
+       case SENSOR_SOI968:
+       case SENSOR_OV9655:
+       case SENSOR_OV9650:
+               exp[0] |= (3 << 4);
+               exp[2] = 0x2d;
+               exp[3] = sd->exposure & 0xff;
+               exp[4] = sd->exposure >> 8;
+               break;
+       case SENSOR_MT9M001:
+       case SENSOR_MT9M111:
+       case SENSOR_MT9V112:
+       case SENSOR_MT9V111:
+       case SENSOR_MT9V011:
+               exp[0] |= (3 << 4);
+               exp[2] = 0x09;
+               exp[3] = sd->exposure >> 8;
+               exp[4] = sd->exposure & 0xff;
+               break;
+       case SENSOR_HV7131R:
+               exp[0] |= (4 << 4);
+               exp[2] = 0x25;
+               exp[3] = ((sd->exposure * 0xffffff) / 0xffff) >> 16;
+               exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
+               exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
+               break;
+       }
+       i2c_w(gspca_dev, exp);
+       return 0;
+}
+
+static int set_gain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+       case SENSOR_OV7670:
+       case SENSOR_SOI968:
+       case SENSOR_OV9655:
+       case SENSOR_OV9650:
+               gain[0] |= (2 << 4);
+               gain[3] = ov_gain[sd->gain];
+               break;
+       case SENSOR_MT9V011:
+       case SENSOR_MT9V111:
+               gain[0] |= (3 << 4);
+               gain[2] = 0x35;
+               gain[3] = micron1_gain[sd->gain] >> 8;
+               gain[4] = micron1_gain[sd->gain] & 0xff;
+               break;
+       case SENSOR_MT9V112:
+       case SENSOR_MT9M111:
+               gain[0] |= (3 << 4);
+               gain[2] = 0x2f;
+               gain[3] = micron1_gain[sd->gain] >> 8;
+               gain[4] = micron1_gain[sd->gain] & 0xff;
+               break;
+       case SENSOR_MT9M001:
+               gain[0] |= (3 << 4);
+               gain[2] = 0x2f;
+               gain[3] = micron2_gain[sd->gain] >> 8;
+               gain[4] = micron2_gain[sd->gain] & 0xff;
+               break;
+       case SENSOR_HV7131R:
+               gain[0] |= (2 << 4);
+               gain[2] = 0x30;
+               gain[3] = hv7131r_gain[sd->gain];
+               break;
+       }
+       i2c_w(gspca_dev, gain);
+       return 0;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               return set_cmatrix(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->brightness;
+       return 0;
+}
+
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               return set_cmatrix(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->saturation = val;
+       if (gspca_dev->streaming)
+               return set_cmatrix(gspca_dev);
+       return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->saturation;
+       return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = val;
+       if (gspca_dev->streaming)
+               return set_cmatrix(gspca_dev);
+       return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->hue;
+       return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming)
+               return set_gamma(gspca_dev);
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->gamma;
+       return 0;
+}
+
+static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->red = val;
+       if (gspca_dev->streaming)
+               return set_redblue(gspca_dev);
+       return 0;
+}
+
+static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->red;
+       return 0;
+}
+
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->blue = val;
+       if (gspca_dev->streaming)
+               return set_redblue(gspca_dev);
+       return 0;
+}
+
+static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->blue;
+       return 0;
+}
+
+static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hflip = val;
+       if (gspca_dev->streaming)
+               return set_hvflip(gspca_dev);
+       return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->hflip;
+       return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->vflip = val;
+       if (gspca_dev->streaming)
+               return set_hvflip(gspca_dev);
+       return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->vflip;
+       return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->exposure = val;
+       if (gspca_dev->streaming)
+               return set_exposure(gspca_dev);
+       return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->exposure;
+       return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gain = val;
+       if (gspca_dev->streaming)
+               return set_gain(gspca_dev);
+       return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->gain;
+       return 0;
+}
+
+static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       sd->auto_exposure = val;
+       return 0;
+}
+
+static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->auto_exposure;
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
+                       struct v4l2_dbg_register *reg)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               if (reg->match.addr != 0)
+                       return -EINVAL;
+               if (reg->reg < 0x1000 || reg->reg > 0x11ff)
+                       return -EINVAL;
+               if (reg_r(gspca_dev, reg->reg, 1) < 0)
+                       return -EINVAL;
+               reg->val = gspca_dev->usb_buf[0];
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               if (reg->match.addr != sd->i2c_addr)
+                       return -EINVAL;
+               if (sd->sensor >= SENSOR_MT9V011 &&
+                   sd->sensor <= SENSOR_MT9M111) {
+                       if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
+                               return -EINVAL;
+               } else {
+                       if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
+                               return -EINVAL;
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
+                       struct v4l2_dbg_register *reg)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               if (reg->match.addr != 0)
+                       return -EINVAL;
+               if (reg->reg < 0x1000 || reg->reg > 0x11ff)
+                       return -EINVAL;
+               if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               if (reg->match.addr != sd->i2c_addr)
+                       return -EINVAL;
+               if (sd->sensor >= SENSOR_MT9V011 &&
+                   sd->sensor <= SENSOR_MT9M111) {
+                       if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
+                               return -EINVAL;
+               } else {
+                       if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
+                               return -EINVAL;
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+#endif
+
+static int sd_chip_ident(struct gspca_dev *gspca_dev,
+                       struct v4l2_dbg_chip_ident *chip)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (chip->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               if (chip->match.addr != 0)
+                       return -EINVAL;
+               chip->revision = 0;
+               chip->ident = V4L2_IDENT_SN9C20X;
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               if (chip->match.addr != sd->i2c_addr)
+                       return -EINVAL;
+               chip->revision = 0;
+               chip->ident = i2c_ident[sd->sensor];
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+
+       sd->sensor = (id->driver_info >> 8) & 0xff;
+       sd->i2c_addr = id->driver_info & 0xff;
+
+       switch (sd->sensor) {
+       case SENSOR_OV9650:
+               cam->cam_mode = sxga_mode;
+               cam->nmodes = ARRAY_SIZE(sxga_mode);
+               break;
+       default:
+               cam->cam_mode = vga_mode;
+               cam->nmodes = ARRAY_SIZE(vga_mode);
+       }
+
+       sd->old_step = 0;
+       sd->older_step = 0;
+       sd->exposure_step = 16;
+
+       sd->brightness = BRIGHTNESS_DEFAULT;
+       sd->contrast = CONTRAST_DEFAULT;
+       sd->saturation = SATURATION_DEFAULT;
+       sd->hue = HUE_DEFAULT;
+       sd->gamma = GAMMA_DEFAULT;
+       sd->red = RED_DEFAULT;
+       sd->blue = BLUE_DEFAULT;
+
+       sd->hflip = HFLIP_DEFAULT;
+       sd->vflip = VFLIP_DEFAULT;
+       sd->exposure = EXPOSURE_DEFAULT;
+       sd->gain = GAIN_DEFAULT;
+       sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
+
+       sd->quality = 95;
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+       sd->input_gpio = (id->driver_info >> 16) & 0xff;
+       if (sn9c20x_input_init(gspca_dev) < 0)
+               return -ENODEV;
+#endif
+       return 0;
+}
+
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       u8 value;
+       u8 i2c_init[9] =
+               {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
+
+       for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
+               value = bridge_init[i][1];
+               if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+                       err("Device initialization failed");
+                       return -ENODEV;
+               }
+       }
+
+       if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+               err("Device initialization failed");
+               return -ENODEV;
+       }
+
+       switch (sd->sensor) {
+       case SENSOR_OV9650:
+               if (ov9650_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("OV9650 sensor detected");
+               break;
+       case SENSOR_OV9655:
+               if (ov9655_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("OV9655 sensor detected");
+               break;
+       case SENSOR_SOI968:
+               if (soi968_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("SOI968 sensor detected");
+               break;
+       case SENSOR_OV7660:
+               if (ov7660_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("OV7660 sensor detected");
+               break;
+       case SENSOR_OV7670:
+               if (ov7670_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("OV7670 sensor detected");
+               break;
+       case SENSOR_MT9VPRB:
+               if (mt9v_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               break;
+       case SENSOR_MT9M111:
+               if (mt9m111_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("MT9M111 sensor detected");
+               break;
+       case SENSOR_MT9M001:
+               if (mt9m001_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("MT9M001 sensor detected");
+               break;
+       case SENSOR_HV7131R:
+               if (hv7131r_init_sensor(gspca_dev) < 0)
+                       return -ENODEV;
+               info("HV7131R sensor detected");
+               break;
+       default:
+               info("Unsupported Sensor");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 value;
+       switch (sd->sensor) {
+       case SENSOR_OV9650:
+               if (mode & MODE_SXGA) {
+                       i2c_w1(gspca_dev, 0x17, 0x1b);
+                       i2c_w1(gspca_dev, 0x18, 0xbc);
+                       i2c_w1(gspca_dev, 0x19, 0x01);
+                       i2c_w1(gspca_dev, 0x1a, 0x82);
+                       i2c_r1(gspca_dev, 0x12, &value);
+                       i2c_w1(gspca_dev, 0x12, value & 0x07);
+               } else {
+                       i2c_w1(gspca_dev, 0x17, 0x24);
+                       i2c_w1(gspca_dev, 0x18, 0xc5);
+                       i2c_w1(gspca_dev, 0x19, 0x00);
+                       i2c_w1(gspca_dev, 0x1a, 0x3c);
+                       i2c_r1(gspca_dev, 0x12, &value);
+                       i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
+               }
+               break;
+       }
+}
+
+#define HW_WIN(mode, hstart, vstart) \
+((const u8 []){hstart & 0xff, hstart >> 8, \
+vstart & 0xff, vstart >> 8, \
+(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
+(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
+
+#define CLR_WIN(width, height) \
+((const u8 [])\
+{0, width >> 2, 0, height >> 1,\
+((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       int width = gspca_dev->width;
+       int height = gspca_dev->height;
+       u8 fmt, scale = 0;
+
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (sd->jpeg_hdr == NULL)
+               return -ENOMEM;
+
+       jpeg_define(sd->jpeg_hdr, height, width,
+                       0x21);
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+       if (mode & MODE_RAW)
+               fmt = 0x2d;
+       else if (mode & MODE_JPEG)
+               fmt = 0x2c;
+       else
+               fmt = 0x2f;
+
+       switch (mode & 0x0f) {
+       case 3:
+               scale = 0xc0;
+               info("Set 1280x1024");
+               break;
+       case 2:
+               scale = 0x80;
+               info("Set 640x480");
+               break;
+       case 1:
+               scale = 0x90;
+               info("Set 320x240");
+               break;
+       case 0:
+               scale = 0xa0;
+               info("Set 160x120");
+               break;
+       }
+
+       configure_sensor_output(gspca_dev, mode);
+       reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
+       reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+       reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
+       reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
+       reg_w1(gspca_dev, 0x1189, scale);
+       reg_w1(gspca_dev, 0x10e0, fmt);
+
+       set_cmatrix(gspca_dev);
+       set_gamma(gspca_dev);
+       set_redblue(gspca_dev);
+       set_gain(gspca_dev);
+       set_exposure(gspca_dev);
+       set_hvflip(gspca_dev);
+
+       reg_r(gspca_dev, 0x1061, 1);
+       reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
+       return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       reg_r(gspca_dev, 0x1061, 1);
+       reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       kfree(sd->jpeg_hdr);
+}
+
+static void do_autoexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int avg_lum, new_exp;
+
+       if (!sd->auto_exposure)
+               return;
+
+       avg_lum = atomic_read(&sd->avg_lum);
+
+       /*
+        * some hardcoded values are present
+        * like those for maximal/minimal exposure
+        * and exposure steps
+        */
+       if (avg_lum < MIN_AVG_LUM) {
+               if (sd->exposure > 0x1770)
+                       return;
+
+               new_exp = sd->exposure + sd->exposure_step;
+               if (new_exp > 0x1770)
+                       new_exp = 0x1770;
+               if (new_exp < 0x10)
+                       new_exp = 0x10;
+               sd->exposure = new_exp;
+               set_exposure(gspca_dev);
+
+               sd->older_step = sd->old_step;
+               sd->old_step = 1;
+
+               if (sd->old_step ^ sd->older_step)
+                       sd->exposure_step /= 2;
+               else
+                       sd->exposure_step += 2;
+       }
+       if (avg_lum > MAX_AVG_LUM) {
+               if (sd->exposure < 0x10)
+                       return;
+               new_exp = sd->exposure - sd->exposure_step;
+               if (new_exp > 0x1700)
+                       new_exp = 0x1770;
+               if (new_exp < 0x10)
+                       new_exp = 0x10;
+               sd->exposure = new_exp;
+               set_exposure(gspca_dev);
+               sd->older_step = sd->old_step;
+               sd->old_step = 0;
+
+               if (sd->old_step ^ sd->older_step)
+                       sd->exposure_step /= 2;
+               else
+                       sd->exposure_step += 2;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       u8 *data,                       /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int avg_lum;
+       static unsigned char frame_header[] =
+               {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+       if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+               avg_lum = ((data[35] >> 2) & 3) |
+                          (data[20] << 2) |
+                          (data[19] << 10);
+               avg_lum += ((data[35] >> 4) & 3) |
+                           (data[22] << 2) |
+                           (data[21] << 10);
+               avg_lum += ((data[35] >> 6) & 3) |
+                           (data[24] << 2) |
+                           (data[23] << 10);
+               avg_lum += (data[36] & 3) |
+                          (data[26] << 2) |
+                          (data[25] << 10);
+               avg_lum += ((data[36] >> 2) & 3) |
+                           (data[28] << 2) |
+                           (data[27] << 10);
+               avg_lum += ((data[36] >> 4) & 3) |
+                           (data[30] << 2) |
+                           (data[29] << 10);
+               avg_lum += ((data[36] >> 6) & 3) |
+                           (data[32] << 2) |
+                           (data[31] << 10);
+               avg_lum += ((data[44] >> 4) & 3) |
+                           (data[34] << 2) |
+                           (data[33] << 10);
+               avg_lum >>= 9;
+               atomic_set(&sd->avg_lum, avg_lum);
+               gspca_frame_add(gspca_dev, LAST_PACKET,
+                               frame, data, len);
+               return;
+       }
+       if (gspca_dev->last_packet_type == LAST_PACKET) {
+               if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
+                               & MODE_JPEG) {
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               sd->jpeg_hdr, JPEG_HDR_SZ);
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                               data, len);
+               } else {
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, len);
+               }
+       } else {
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+       }
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .pkt_scan = sd_pkt_scan,
+       .dq_callback = do_autoexposure,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .set_register = sd_dbg_s_register,
+       .get_register = sd_dbg_g_register,
+#endif
+       .get_chip_ident = sd_chip_ident,
+};
+
+#define SN9C20X(sensor, i2c_addr, button_mask) \
+       .driver_info =  (button_mask << 16) \
+                       | (SENSOR_ ## sensor << 8) \
+                       | (i2c_addr)
+
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
+       {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
+       {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, 0x10)},
+       {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
+       {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
+       {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
+       {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
+       {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
+       {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
+       {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
+       {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
+       {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static void sd_disconnect(struct usb_interface *intf)
+{
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+       struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+       sn9c20x_input_cleanup(gspca_dev);
+#endif
+
+       gspca_disconnect(intf);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = sd_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+       .reset_resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       info("registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 0d02f41fa7d099835e390c23e957806c277b4f16..d6332ab80669218cdfa1d5b0fdd3a61874be9fc5 100644 (file)
@@ -1634,6 +1634,8 @@ static void setfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
+               return;
        if (sd->sensor == SENSOR_OV7660) {
                switch (sd->freq) {
                case 0: /* Banding filter disabled */
@@ -1735,6 +1737,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index 8806b2ff82bece047379e53fe80ef92c1e629ba2..fab7ef85a6c1dc34f9ca1c4e4f7e12febf6b560a 100644 (file)
@@ -670,6 +670,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index f25be20cf1a6f0865e6e8a1757076d2bc6ef4cf3..47628964801e6c350c685ef99529068a9fccdbd7 100644 (file)
@@ -333,6 +333,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index 3039ec208f3a5e37c029cc44876642eb0611867f..e5024c8496ef75ddd5f35f2f325b77c0c8c4d853 100644 (file)
@@ -64,7 +64,7 @@ static struct v4l2_pix_format hdcs1x00_mode[] = {
        {
                HDCS_1X00_DEF_WIDTH,
                HDCS_1X00_DEF_HEIGHT,
-               V4L2_PIX_FMT_SBGGR8,
+               V4L2_PIX_FMT_SGRBG8,
                V4L2_FIELD_NONE,
                .sizeimage =
                        HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
@@ -80,7 +80,7 @@ static struct v4l2_pix_format hdcs1020_mode[] = {
        {
                HDCS_1020_DEF_WIDTH,
                HDCS_1020_DEF_HEIGHT,
-               V4L2_PIX_FMT_SBGGR8,
+               V4L2_PIX_FMT_SGRBG8,
                V4L2_FIELD_NONE,
                .sizeimage =
                        HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
@@ -131,9 +131,11 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
                     (reg + len > 0xff)))
                return -EINVAL;
 
-       for (i = 0; i < len; i++, reg++) {
-               regs[2*i] = reg;
-               regs[2*i+1] = vals[i];
+       for (i = 0; i < len; i++) {
+               regs[2 * i] = reg;
+               regs[2 * i + 1] = vals[i];
+               /* All addresses are shifted left one bit as bit 0 toggles r/w */
+               reg += 2;
        }
 
        return stv06xx_write_sensor_bytes(sd, regs, len);
@@ -174,7 +176,9 @@ static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
        }
 
        ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
-       if (ret < 0)
+
+       /* Update the state if the write succeeded */
+       if (!ret)
                hdcs->state = state;
 
        return ret;
index 9623f294bdac1aada92418a7b58f0cbf80a21819..5127bbf9dd260ed519397f535953c830e67d16ea 100644 (file)
@@ -973,6 +973,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index 08422d315e68023a10c94570b192dffa8e8c2503..3d2756f7874adac447954820267bf519198f53f8 100644 (file)
@@ -7243,6 +7243,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
index 1fe8fc9183a777cc6bf9d8310824f6a4f4db6194..b2260de645f0c16855dfd31ac8aa4b296a05f34f 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <linux/delay.h>
+#include <asm/div64.h>
 #include <media/v4l2-device.h>
 #include "mt9v011.h"
 #include <media/v4l2-i2c-drv.h>
@@ -57,6 +58,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
 struct mt9v011 {
        struct v4l2_subdev sd;
        unsigned width, height;
+       unsigned xtal;
 
        u16 global_gain, red_bal, blue_bal;
 };
@@ -131,7 +133,7 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
                { R1E_MT9V011_DIGITAL_ZOOM,  0x0000 },
                { R20_MT9V011_READ_MODE, 0x1000 },
 
-               { R07_MT9V011_OUT_CTRL, 0x000a },       /* chip enable */
+               { R07_MT9V011_OUT_CTRL, 0x0002 },       /* chip enable */
 };
 
 static void set_balance(struct v4l2_subdev *sd)
@@ -154,6 +156,31 @@ static void set_balance(struct v4l2_subdev *sd)
        mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
 }
 
+static void calc_fps(struct v4l2_subdev *sd)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+       unsigned height, width, hblank, vblank, speed;
+       unsigned row_time, t_time;
+       u64 frames_per_ms;
+       unsigned tmp;
+
+       height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
+       width = mt9v011_read(sd, R04_MT9V011_WIDTH);
+       hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
+       vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
+       speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED);
+
+       row_time = (width + 113 + hblank) * (speed + 2);
+       t_time = row_time * (height + vblank + 1);
+
+       frames_per_ms = core->xtal * 1000l;
+       do_div(frames_per_ms, t_time);
+       tmp = frames_per_ms;
+
+       v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n",
+               tmp / 1000, tmp % 1000, t_time);
+}
+
 static void set_res(struct v4l2_subdev *sd)
 {
        struct mt9v011 *core = to_mt9v011(sd);
@@ -175,10 +202,12 @@ static void set_res(struct v4l2_subdev *sd)
        mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
        mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
 
-       vstart = 8 + (640 - core->height) / 2;
+       vstart = 8 + (480 - core->height) / 2;
        mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
        mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
        mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
+
+       calc_fps(sd);
 };
 
 static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
@@ -215,6 +244,23 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return -EINVAL;
 }
 
+static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       v4l2_dbg(1, debug, sd, "queryctrl called\n");
+
+       for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++)
+               if (qc->id && qc->id == mt9v011_qctrl[i].id) {
+                       memcpy(qc, &(mt9v011_qctrl[i]),
+                              sizeof(*qc));
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
 static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        struct mt9v011 *core = to_mt9v011(sd);
@@ -294,6 +340,22 @@ static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
        return 0;
 }
 
+static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
+{
+       struct mt9v011 *core = to_mt9v011(sd);
+       unsigned *xtal = data;
+
+       v4l2_dbg(1, debug, sd, "s_config called\n");
+
+       if (xtal) {
+               core->xtal = *xtal;
+               v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+                        *xtal / 1000000, (*xtal / 1000) % 1000);
+       }
+
+       return 0;
+}
+
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9v011_g_register(struct v4l2_subdev *sd,
@@ -338,9 +400,11 @@ static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
 }
 
 static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
+       .queryctrl = mt9v011_queryctrl,
        .g_ctrl = mt9v011_g_ctrl,
        .s_ctrl = mt9v011_s_ctrl,
        .reset = mt9v011_reset,
+       .s_config = mt9v011_s_config,
        .g_chip_ident = mt9v011_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = mt9v011_g_register,
@@ -395,6 +459,7 @@ static int mt9v011_probe(struct i2c_client *c,
        core->global_gain = 0x0024;
        core->width  = 640;
        core->height = 480;
+       core->xtal = 27000000;  /* Hz */
 
        v4l_info(c, "chip found @ 0x%02x (%s)\n",
                 c->addr << 1, c->adapter->name);
index db25c3034c11be4e7deb4cc98bf41006b4e860f7..8d17cf61330671f1d71c94dfc82a689f7b0bbf69 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/usb/input.h>
 #endif
index 0be6f814f5396cb7615484201db3a45a46f98ac5..0b658dee05a41f047fa55f171c4972fc5b140aa3 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/usb.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>
 #include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
index 6be845ccc7d7e7412f97b2e65c32e6cd3deb091e..9e3262c0ba371b1c935100504b8e6444964f7d51 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
index 155804b061e948b091b997242dec8ab8c1edd5c1..b624a4c01fdc9faee6e2fe37ad0939da9fdbfee2 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/videotext.h>
 #include <linux/videodev2.h>
index 271d6e931b750ecd9b7c0ee4a499f52a3833476f..12835fb82c9557c56d09d16825d954dd0d24920e 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/videotext.h>
index add1757f89303851afa45f49d5c6975641efde9b..296788c3bf0ecc6ddc14301fb10bf198216e155a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/delay.h>
 
 #include "saa7134-reg.h"
index c8f05297d0f0680acccc7513231a5e561c57b3db..85ffc2cba039b3e6114e5fc8d3bd4671bf9fea20 100644 (file)
@@ -31,6 +31,7 @@ static const char version[] = "0.24";
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/usb.h>
 #include "se401.h"
index 2e59370472788712ba3e08ae62dd2b5f2b62f2e0..4d6785e634556fbba9bc87a89708302907f40a0c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 
 #include <linux/usb.h>
 #include <linux/mm.h>
index 0eb313082c973e78fcfe6e2e935ec1c5751ce5c6..eaada39c76fdfcf5d2273bd3c31af6dca0350da1 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
index 75f286f7a2e9939cfc9d24f25a06d6b50c8cab91..8b4e7dafce7b9d155c254a802282daa0f25f1570 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/errno.h>
 #include <linux/videodev.h>
index 8d73979596f9d9542c35e10aa158d6792878099a..45fce39ec9ad56b77c5b7db00eca8dccf3d5a0f3 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/firmware.h>
 #include <linux/ihex.h>
index 90b58914f98472644e289c97ce02297490c920d2..90d9b5c0e9a7bc407806e357a32988ed61df5b0e 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/highmem.h>
index 31eac66411d736e4330119900e111aa921e841e4..a7f1b69a7dab398522ea9ca994c998be82719063 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index 3d7df32a3d8706d30ac56a88fcbc720e7a25a6d6..bcdefb1bcb3dc450a54b0c05fb9e58c7dd91c81b 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
index fa2d93a9fb8d7755de89a2f08badce29a07f8983..aed609832bc2bf1c0497dedbd0257bcfcbf7e70a 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/io.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
index eedbf9c32760f68b76a34726a8358244e1834389..79689b10f937e0b8405a6a3568d5503c532d64a9 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
index b56d72ff06e9efbf169d5b2f0c7af2c4f6e7589e..34e23489811ae74ea14594f1af1cb84f7a6e6b58 100644 (file)
@@ -384,7 +384,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
                                u16 val[2] = {0, 0};
                                val[0] = mvsd_read(MVSD_FIFO);
                                val[1] = mvsd_read(MVSD_FIFO);
-                               memcpy(p, &val, s);
+                               memcpy(p, ((void *)&val) + 4 - s, s);
                                s = 0;
                                intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
                        }
@@ -423,7 +423,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
                if (s < 4) {
                        if (s && (intr_status & MVSD_NOR_TX_AVAIL)) {
                                u16 val[2] = {0, 0};
-                               memcpy(&val, p, s);
+                               memcpy(((void *)&val) + 4 - s, p, s);
                                mvsd_write(MVSD_FIFO, val[0]);
                                mvsd_write(MVSD_FIFO, val[1]);
                                s = 0;
index d7d7109ef47e10b665059433ec962db77f176f7d..e55ac792d68c700e2bfc0d9b86d992c5f4199faf 100644 (file)
@@ -168,12 +168,12 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 
        if (data->flags & MMC_DATA_READ) {
                host->dma_dir = DMA_FROM_DEVICE;
-               dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+               dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
                DRCMR(host->dma_drcmrtx) = 0;
                DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
        } else {
                host->dma_dir = DMA_TO_DEVICE;
-               dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+               dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
                DRCMR(host->dma_drcmrrx) = 0;
                DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
        }
index 286ed594e5a0ec01d87810c004e0511b78385477..e1f7d0a78b9d58e28a2b6c1fdad43423cddd3956 100644 (file)
@@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
        if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
                ubi->bad_allowed = 1;
 
+       if (ubi->mtd->type == MTD_NORFLASH) {
+               ubi_assert(ubi->mtd->writesize == 1);
+               ubi->nor_flash = 1;
+       }
+
        ubi->min_io_size = ubi->mtd->writesize;
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
@@ -996,6 +1001,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
        ubi_msg("number of PEBs reserved for bad PEB handling: %d",
                ubi->beb_rsvd_pebs);
        ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+       ubi_msg("image sequence number: %d", ubi->image_seq);
 
        /*
         * The below lock makes sure we do not race with 'ubi_thread()' which
index c0ed60e8ade978ca74091aed6a8e5b14f1a47e63..54b0186915fbf6ab6be8f845a4d942f7f2f277aa 100644 (file)
@@ -44,6 +44,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
               be32_to_cpu(ec_hdr->vid_hdr_offset));
        printk(KERN_DEBUG "\tdata_offset    %d\n",
               be32_to_cpu(ec_hdr->data_offset));
+       printk(KERN_DEBUG "\timage_seq      %d\n",
+              be32_to_cpu(ec_hdr->image_seq));
        printk(KERN_DEBUG "\thdr_crc        %#08x\n",
               be32_to_cpu(ec_hdr->hdr_crc));
        printk(KERN_DEBUG "erase counter header hexdump:\n");
index 13777e5beac93344ae759aa2ea0176c796e97d1d..a4da7a09b949b75f5e259837da31190b31874bbc 100644 (file)
@@ -93,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 #define UBI_IO_DEBUG 0
 #endif
 
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
+#else
+#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+#endif
+
 #ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
 #define DBG_DISABLE_BGT 1
 #else
@@ -167,6 +173,7 @@ static inline int ubi_dbg_is_erase_failure(void)
 #define ubi_dbg_is_bitflip()       0
 #define ubi_dbg_is_write_failure() 0
 #define ubi_dbg_is_erase_failure() 0
+#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
 
 #endif /* !CONFIG_MTD_UBI_DEBUG */
 #endif /* !__UBI_DEBUG_H__ */
index 95aaac03f9389a8727b3ed65f91124dc592c15dc..b5e478fa26612b188aa664541503457b2e58d2af 100644 (file)
@@ -332,6 +332,7 @@ static int gluebi_create(struct ubi_device_info *di,
        }
 
        gluebi->vol_id = vi->vol_id;
+       gluebi->ubi_num = vi->ubi_num;
        mtd->type = MTD_UBIVOLUME;
        if (!di->ro_mode)
                mtd->flags = MTD_WRITEABLE;
index effaff28bab18ef4936c69cf354a4b8a11db17dd..4cb69925d8d968f9021626a6dd38933af94842ee 100644 (file)
@@ -98,17 +98,12 @@ 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(struct ubi_device *ubi, int pnum, int offset,
-                                int len);
-static int paranoid_check_empty(struct ubi_device *ubi, int pnum);
 #else
 #define paranoid_check_not_bad(ubi, pnum) 0
 #define paranoid_check_peb_ec_hdr(ubi, pnum)  0
 #define paranoid_check_ec_hdr(ubi, pnum, ec_hdr)  0
 #define paranoid_check_peb_vid_hdr(ubi, pnum) 0
 #define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
-#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
-#define paranoid_check_empty(ubi, pnum) 0
 #endif
 
 /**
@@ -244,7 +239,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
                return err > 0 ? -EINVAL : err;
 
        /* The area we are writing to has to contain all 0xFF bytes */
-       err = paranoid_check_all_ff(ubi, pnum, offset, len);
+       err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
        if (err)
                return err > 0 ? -EINVAL : err;
 
@@ -271,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
        addr = (loff_t)pnum * ubi->peb_size + offset;
        err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
        if (err) {
-               ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
-                       " %zd bytes", err, len, pnum, offset, written);
+               ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
+                       "%zd bytes", err, len, pnum, offset, written);
                ubi_dbg_dump_stack();
        } else
                ubi_assert(written == len);
@@ -350,7 +345,7 @@ retry:
                return -EIO;
        }
 
-       err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+       err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
        if (err)
                return err > 0 ? -EINVAL : err;
 
@@ -458,6 +453,54 @@ out:
        return err;
 }
 
+/**
+ * nor_erase_prepare - prepare a NOR flash PEB for erasure.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to prepare
+ *
+ * NOR flash, or at least some of them, have peculiar embedded PEB erasure
+ * algorithm: the PEB is first filled with zeroes, then it is erased. And
+ * filling with zeroes starts from the end of the PEB. This was observed with
+ * Spansion S29GL512N NOR flash.
+ *
+ * This means that in case of a power cut we may end up with intact data at the
+ * beginning of the PEB, and all zeroes at the end of PEB. In other words, the
+ * EC and VID headers are OK, but a large chunk of data at the end of PEB is
+ * zeroed. This makes UBI mistakenly treat this PEB as used and associate it
+ * with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
+ *
+ * This function is called before erasing NOR PEBs and it zeroes out EC and VID
+ * magic numbers in order to invalidate them and prevent the failures. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
+{
+       int err;
+       size_t written;
+       loff_t addr;
+       uint32_t data = 0;
+
+       addr = (loff_t)pnum * ubi->peb_size;
+       err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
+       if (err) {
+               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
+                       "%zd bytes", err, pnum, 0, written);
+               ubi_dbg_dump_stack();
+               return err;
+       }
+
+       addr += ubi->vid_hdr_aloffset;
+       err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
+       if (err) {
+               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
+                       "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
+               ubi_dbg_dump_stack();
+               return err;
+       }
+
+       return 0;
+}
+
 /**
  * ubi_io_sync_erase - synchronously erase a physical eraseblock.
  * @ubi: UBI device description object
@@ -489,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
                return -EROFS;
        }
 
+       if (ubi->nor_flash) {
+               err = nor_erase_prepare(ubi, pnum);
+               if (err)
+                       return err;
+       }
+
        if (torture) {
                ret = torture_peb(ubi, pnum);
                if (ret < 0)
@@ -672,11 +721,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                if (read_err != -EBADMSG &&
                    check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly empty */
-                       err = paranoid_check_all_ff(ubi, pnum, 0,
-                                                   ubi->peb_size);
-                       if (err)
-                               return err > 0 ? UBI_IO_BAD_EC_HDR : err;
-
                        if (verbose)
                                ubi_warn("no EC header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
@@ -752,6 +796,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
        ec_hdr->version = UBI_VERSION;
        ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
        ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
+       ec_hdr->image_seq = cpu_to_be32(ubi->image_seq);
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
        ec_hdr->hdr_crc = cpu_to_be32(crc);
 
@@ -947,15 +992,6 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                if (read_err != -EBADMSG &&
                    check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly free */
-
-                       /*
-                        * The below is just a paranoid check, it has to be
-                        * compiled out if paranoid checks are disabled.
-                        */
-                       err = paranoid_check_empty(ubi, pnum);
-                       if (err)
-                               return err > 0 ? UBI_IO_BAD_VID_HDR : err;
-
                        if (verbose)
                                ubi_warn("no VID header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
@@ -1229,7 +1265,7 @@ exit:
 }
 
 /**
- * paranoid_check_all_ff - check that a region of flash is empty.
+ * ubi_dbg_check_all_ff - check that a region of flash is empty.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock number to check
  * @offset: the starting offset within the physical eraseblock to check
@@ -1239,8 +1275,7 @@ 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(struct ubi_device *ubi, int pnum, int offset,
-                                int len)
+int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 {
        size_t read;
        int err;
@@ -1276,74 +1311,4 @@ error:
        return err;
 }
 
-/**
- * paranoid_check_empty - whether a PEB is empty.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to check
- *
- * This function makes sure PEB @pnum is empty, which means it contains only
- * %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a
- * negative error code in case of failure.
- *
- * Empty PEBs have the EC header, and do not have the VID header. The caller of
- * this function should have already made sure the PEB does not have the VID
- * header. However, this function re-checks that, because it is possible that
- * the header and data has already been written to the PEB.
- *
- * Let's consider a possible scenario. Suppose there are 2 tasks - A and B.
- * Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to
- * find which LEB it corresponds to. PEB X is currently unmapped, and has no
- * VID header. Task B is trying to write to PEB X.
- *
- * Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The
- *         read data contain all 0xFF bytes;
- * Task B: writes VID header and some data to PEB X;
- * Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we
- *         do not re-read the VID header, and do not cancel the checking if it
- *         is there, we fail.
- */
-static int paranoid_check_empty(struct ubi_device *ubi, int pnum)
-{
-       int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize;
-       size_t read;
-       uint32_t magic;
-       const struct ubi_vid_hdr *vid_hdr;
-
-       mutex_lock(&ubi->dbg_buf_mutex);
-       err = ubi->mtd->read(ubi->mtd, offs, 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, offs, read);
-               goto error;
-       }
-
-       vid_hdr = ubi->dbg_peb_buf;
-       magic = be32_to_cpu(vid_hdr->magic);
-       if (magic == UBI_VID_HDR_MAGIC)
-               /* The PEB contains VID header, so it is not empty */
-               goto out;
-
-       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, offs, len);
-               goto fail;
-       }
-
-out:
-       mutex_unlock(&ubi->dbg_buf_mutex);
-       return 0;
-
-fail:
-       ubi_err("paranoid check failed for PEB %d", pnum);
-       ubi_msg("hex dump of the %d-%d region", offs, offs + len);
-       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-                      ubi->dbg_peb_buf, len, 1);
-       err = 1;
-error:
-       ubi_dbg_dump_stack();
-       mutex_unlock(&ubi->dbg_buf_mutex);
-       return err;
-}
-
 #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
index c3d653ba5ca0153c45ccbfd21a6d106bfa1b6220..a423131b617141faaaf7b998e49ceb8b23146fce 100644 (file)
@@ -757,6 +757,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
        si->is_empty = 0;
 
        if (!ec_corr) {
+               int image_seq;
+
                /* Make sure UBI version is OK */
                if (ech->version != UBI_VERSION) {
                        ubi_err("this UBI version is %d, image version is %d",
@@ -778,6 +780,18 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                        ubi_dbg_dump_ec_hdr(ech);
                        return -EINVAL;
                }
+
+               image_seq = be32_to_cpu(ech->image_seq);
+               if (!si->image_seq_set) {
+                       ubi->image_seq = image_seq;
+                       si->image_seq_set = 1;
+               } else if (ubi->image_seq != image_seq) {
+                       ubi_err("bad image sequence number %d in PEB %d, "
+                               "expected %d", image_seq, pnum, ubi->image_seq);
+                       ubi_dbg_dump_ec_hdr(ech);
+                       return -EINVAL;
+               }
+
        }
 
        /* OK, we've done with the EC header, let's look at the VID header */
index 61df208e2f2077de860db28494e8639349368111..1017cf12def56253606168e3c2ad18af674b8eae 100644 (file)
@@ -102,6 +102,7 @@ struct ubi_scan_volume {
  * @mean_ec: mean erase counter value
  * @ec_sum: a temporary variable used when calculating @mean_ec
  * @ec_count: a temporary variable used when calculating @mean_ec
+ * @image_seq_set: indicates @ubi->image_seq is known
  *
  * This data structure contains the result of scanning and may be used by other
  * UBI sub-systems to build final UBI data structures, further error-recovery
@@ -124,6 +125,7 @@ struct ubi_scan_info {
        int mean_ec;
        uint64_t ec_sum;
        int ec_count;
+       int image_seq_set;
 };
 
 struct ubi_device;
index 8419fdccc79cbcbdadb639b8188c65eab18bd468..503ea9b273094670d0933baafbfbfb04ae6d88cd 100644 (file)
@@ -129,6 +129,7 @@ enum {
  * @ec: the erase counter
  * @vid_hdr_offset: where the VID header starts
  * @data_offset: where the user data start
+ * @image_seq: image sequence number
  * @padding2: reserved for future, zeroes
  * @hdr_crc: erase counter header CRC checksum
  *
@@ -144,6 +145,14 @@ enum {
  * volume identifier header and user data, relative to the beginning of the
  * physical eraseblock. These values have to be the same for all physical
  * eraseblocks.
+ *
+ * The @image_seq field is used to validate a UBI image that has been prepared
+ * for a UBI device. The @image_seq value can be any value, but it must be the
+ * same on all eraseblocks. UBI will ensure that all new erase counter headers
+ * also contain this value, and will check the value when scanning at start-up.
+ * One way to make use of @image_seq is to increase its value by one every time
+ * an image is flashed over an existing image, then, if the flashing does not
+ * complete, UBI will detect the error when scanning.
  */
 struct ubi_ec_hdr {
        __be32  magic;
@@ -152,7 +161,8 @@ struct ubi_ec_hdr {
        __be64  ec; /* Warning: the current limit is 31-bit anyway! */
        __be32  vid_hdr_offset;
        __be32  data_offset;
-       __u8    padding2[36];
+       __be32  image_seq;
+       __u8    padding2[32];
        __be32  hdr_crc;
 } __attribute__ ((packed));
 
index 28acd133c997987eedefe9c926313a4dd207ffb9..6a5fe963378367ab48f871cbd6893d56d4ed454e 100644 (file)
@@ -301,6 +301,7 @@ struct ubi_wl_entry;
  *                @vol->readers, @vol->writers, @vol->exclusive,
  *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
  * @ref_count: count of references on the UBI device
+ * @image_seq: image sequence number recorded on EC headers
  *
  * @rsvd_pebs: count of reserved physical eraseblocks
  * @avail_pebs: count of available physical eraseblocks
@@ -372,6 +373,7 @@ struct ubi_wl_entry;
  * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
  *               not
+ * @nor_flash: non-zero if working on top of NOR flash
  * @mtd: MTD device descriptor
  *
  * @peb_buf1: a buffer of PEB size used for different purposes
@@ -390,6 +392,7 @@ struct ubi_device {
        struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
        spinlock_t volumes_lock;
        int ref_count;
+       int image_seq;
 
        int rsvd_pebs;
        int avail_pebs;
@@ -452,7 +455,8 @@ struct ubi_device {
        int vid_hdr_offset;
        int vid_hdr_aloffset;
        int vid_hdr_shift;
-       int bad_allowed;
+       unsigned int bad_allowed:1;
+       unsigned int nor_flash:1;
        struct mtd_info *mtd;
 
        void *peb_buf1;
index 2b2472300610f166eb897a53647436f4307c9456..600c7229d5cf21b0d959ca2d7c1a86ccc676e4af 100644 (file)
@@ -459,6 +459,14 @@ retry:
        dbg_wl("PEB %d EC %d", e->pnum, e->ec);
        prot_queue_add(ubi, e);
        spin_unlock(&ubi->wl_lock);
+
+       err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+                                  ubi->peb_size - ubi->vid_hdr_aloffset);
+       if (err) {
+               ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
+               return err > 0 ? -EINVAL : err;
+       }
+
        return e->pnum;
 }
 
index 8ae72ec14456d4dc2e31141777a1bf35776fc78a..0e2ba21d4441810a279432229d7d078ef3e65bdd 100644 (file)
@@ -908,6 +908,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
        .ndo_get_stats          = rtl8139_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = rtl8139_set_mac_address,
        .ndo_start_xmit         = rtl8139_start_xmit,
index c155bd3ec9f1a47640d4706626f544afe2e335bb..5f6509a5f640820fd89b6ef7b8b420a1ab0c8e39 100644 (file)
@@ -1729,6 +1729,13 @@ config KS8842
        help
          This platform driver is for Micrel KSZ8842 chip.
 
+config KS8851
+       tristate "Micrel KS8851 SPI"
+       depends on SPI
+       select MII
+       help
+         SPI driver for Micrel KS8851 SPI attached network chip.
+
 config VIA_RHINE
        tristate "VIA Rhine support"
        depends on NET_PCI && PCI
index 4b58a59f211b4e329e791ae3bf881a7f9edf7a81..ead8cab3cfe1d464dd0294949efaf1f02ec4d3be 100644 (file)
@@ -88,6 +88,7 @@ obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SKY2) += sky2.o
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_KS8842)   += ks8842.o
+obj-$(CONFIG_KS8851)   += ks8851.o
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
index 2895db13bfa4459cebc86b89c2e7dc1fc5971495..c37ee9e6b67b93c989de07689c0c47bad7150d50 100644 (file)
@@ -63,3 +63,11 @@ config IXP4XX_ETH
        help
          Say Y here if you want to use built-in Ethernet ports
          on IXP4xx processor.
+
+config W90P910_ETH
+       tristate "Nuvoton w90p910 Ethernet support"
+       depends on ARM && ARCH_W90X900
+       select PHYLIB
+       help
+         Say Y here if you want to use built-in Ethernet ports
+         on w90p910 processor.
index 811a3ccd14c107c56136af8884022f7cd9f4498f..303171f589e61f2379587f9d13ddbc4b416263e6 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_ARM_AT91_ETHER)  += at91_ether.o
 obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
 obj-$(CONFIG_EP93XX_ETH)       += ep93xx_eth.o
 obj-$(CONFIG_IXP4XX_ETH)       += ixp4xx_eth.o
+obj-$(CONFIG_W90P910_ETH)      += w90p910_ether.o
index 2e7419a6119181b29538720114e59b74bf15c578..5041d10bae9d9611c280ad50b17068349e9decd9 100644 (file)
@@ -1228,7 +1228,6 @@ static int at91ether_resume(struct platform_device *pdev)
 #endif
 
 static struct platform_driver at91ether_driver = {
-       .probe          = at91ether_probe,
        .remove         = __devexit_p(at91ether_remove),
        .suspend        = at91ether_suspend,
        .resume         = at91ether_resume,
@@ -1240,7 +1239,7 @@ static struct platform_driver at91ether_driver = {
 
 static int __init at91ether_init(void)
 {
-       return platform_driver_register(&at91ether_driver);
+       return platform_driver_probe(&at91ether_driver, at91ether_probe);
 }
 
 static void __exit at91ether_exit(void)
index 6f42ad728915b2683ee9ee66a9e11562c890453e..3fe09876e76d3f5c62e0878adf7545317760a2c3 100644 (file)
@@ -1142,7 +1142,9 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
        .ndo_start_xmit = eth_xmit,
        .ndo_set_multicast_list = eth_set_mcast_list,
        .ndo_do_ioctl = eth_ioctl,
-
+       .ndo_change_mtu = eth_change_mtu,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
 };
 
 static int __devinit eth_init_one(struct platform_device *pdev)
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
new file mode 100644 (file)
index 0000000..616fb79
--- /dev/null
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2008-2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#define DRV_MODULE_NAME                "w90p910-emc"
+#define DRV_MODULE_VERSION     "0.1"
+
+/* Ethernet MAC Registers */
+#define REG_CAMCMR             0x00
+#define REG_CAMEN              0x04
+#define REG_CAMM_BASE          0x08
+#define REG_CAML_BASE          0x0c
+#define REG_TXDLSA             0x88
+#define REG_RXDLSA             0x8C
+#define REG_MCMDR              0x90
+#define REG_MIID               0x94
+#define REG_MIIDA              0x98
+#define REG_FFTCR              0x9C
+#define REG_TSDR               0xa0
+#define REG_RSDR               0xa4
+#define REG_DMARFC             0xa8
+#define REG_MIEN               0xac
+#define REG_MISTA              0xb0
+#define REG_CTXDSA             0xcc
+#define REG_CTXBSA             0xd0
+#define REG_CRXDSA             0xd4
+#define REG_CRXBSA             0xd8
+
+/* mac controller bit */
+#define MCMDR_RXON             0x01
+#define MCMDR_ACP              (0x01 << 3)
+#define MCMDR_SPCRC            (0x01 << 5)
+#define MCMDR_TXON             (0x01 << 8)
+#define MCMDR_FDUP             (0x01 << 18)
+#define MCMDR_ENMDC            (0x01 << 19)
+#define MCMDR_OPMOD            (0x01 << 20)
+#define SWR                    (0x01 << 24)
+
+/* cam command regiser */
+#define CAMCMR_AUP             0x01
+#define CAMCMR_AMP             (0x01 << 1)
+#define CAMCMR_ABP             (0x01 << 2)
+#define CAMCMR_CCAM            (0x01 << 3)
+#define CAMCMR_ECMP            (0x01 << 4)
+#define CAM0EN                 0x01
+
+/* mac mii controller bit */
+#define MDCCR                  (0x0a << 20)
+#define PHYAD                  (0x01 << 8)
+#define PHYWR                  (0x01 << 16)
+#define PHYBUSY                        (0x01 << 17)
+#define PHYPRESP               (0x01 << 18)
+#define CAM_ENTRY_SIZE         0x08
+
+/* rx and tx status */
+#define TXDS_TXCP              (0x01 << 19)
+#define RXDS_CRCE              (0x01 << 17)
+#define RXDS_PTLE              (0x01 << 19)
+#define RXDS_RXGD              (0x01 << 20)
+#define RXDS_ALIE              (0x01 << 21)
+#define RXDS_RP                        (0x01 << 22)
+
+/* mac interrupt status*/
+#define MISTA_EXDEF            (0x01 << 19)
+#define MISTA_TXBERR           (0x01 << 24)
+#define MISTA_TDU              (0x01 << 23)
+#define MISTA_RDU              (0x01 << 10)
+#define MISTA_RXBERR           (0x01 << 11)
+
+#define ENSTART                        0x01
+#define ENRXINTR               0x01
+#define ENRXGD                 (0x01 << 4)
+#define ENRXBERR               (0x01 << 11)
+#define ENTXINTR               (0x01 << 16)
+#define ENTXCP                 (0x01 << 18)
+#define ENTXABT                        (0x01 << 21)
+#define ENTXBERR               (0x01 << 24)
+#define ENMDC                  (0x01 << 19)
+#define PHYBUSY                        (0x01 << 17)
+#define MDCCR_VAL              0xa00000
+
+/* rx and tx owner bit */
+#define RX_OWEN_DMA            (0x01 << 31)
+#define RX_OWEN_CPU            (~(0x03 << 30))
+#define TX_OWEN_DMA            (0x01 << 31)
+#define TX_OWEN_CPU            (~(0x01 << 31))
+
+/* tx frame desc controller bit */
+#define MACTXINTEN             0x04
+#define CRCMODE                        0x02
+#define PADDINGMODE            0x01
+
+/* fftcr controller bit */
+#define TXTHD                  (0x03 << 8)
+#define BLENGTH                        (0x01 << 20)
+
+/* global setting for driver */
+#define RX_DESC_SIZE           50
+#define TX_DESC_SIZE           10
+#define MAX_RBUFF_SZ           0x600
+#define MAX_TBUFF_SZ           0x600
+#define TX_TIMEOUT             50
+#define DELAY                  1000
+#define CAM0                   0x0
+
+static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg);
+
+struct w90p910_rxbd {
+       unsigned int sl;
+       unsigned int buffer;
+       unsigned int reserved;
+       unsigned int next;
+};
+
+struct w90p910_txbd {
+       unsigned int mode;
+       unsigned int buffer;
+       unsigned int sl;
+       unsigned int next;
+};
+
+struct recv_pdesc {
+       struct w90p910_rxbd desclist[RX_DESC_SIZE];
+       char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ];
+};
+
+struct tran_pdesc {
+       struct w90p910_txbd desclist[TX_DESC_SIZE];
+       char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ];
+};
+
+struct  w90p910_ether {
+       struct recv_pdesc *rdesc;
+       struct recv_pdesc *rdesc_phys;
+       struct tran_pdesc *tdesc;
+       struct tran_pdesc *tdesc_phys;
+       struct net_device_stats stats;
+       struct platform_device *pdev;
+       struct sk_buff *skb;
+       struct clk *clk;
+       struct clk *rmiiclk;
+       struct mii_if_info mii;
+       struct timer_list check_timer;
+       void __iomem *reg;
+       unsigned int rxirq;
+       unsigned int txirq;
+       unsigned int cur_tx;
+       unsigned int cur_rx;
+       unsigned int finish_tx;
+       unsigned int rx_packets;
+       unsigned int rx_bytes;
+       unsigned int start_tx_ptr;
+       unsigned int start_rx_ptr;
+       unsigned int linkflag;
+       spinlock_t lock;
+};
+
+static void update_linkspeed_register(struct net_device *dev,
+                               unsigned int speed, unsigned int duplex)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = __raw_readl(ether->reg + REG_MCMDR);
+
+       if (speed == SPEED_100) {
+               /* 100 full/half duplex */
+               if (duplex == DUPLEX_FULL) {
+                       val |= (MCMDR_OPMOD | MCMDR_FDUP);
+               } else {
+                       val |= MCMDR_OPMOD;
+                       val &= ~MCMDR_FDUP;
+               }
+       } else {
+               /* 10 full/half duplex */
+               if (duplex == DUPLEX_FULL) {
+                       val |= MCMDR_FDUP;
+                       val &= ~MCMDR_OPMOD;
+               } else {
+                       val &= ~(MCMDR_FDUP | MCMDR_OPMOD);
+               }
+       }
+
+       __raw_writel(val, ether->reg + REG_MCMDR);
+}
+
+static void update_linkspeed(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       struct platform_device *pdev;
+       unsigned int bmsr, bmcr, lpa, speed, duplex;
+
+       pdev = ether->pdev;
+
+       if (!mii_link_ok(&ether->mii)) {
+               ether->linkflag = 0x0;
+               netif_carrier_off(dev);
+               dev_warn(&pdev->dev, "%s: Link down.\n", dev->name);
+               return;
+       }
+
+       if (ether->linkflag == 1)
+               return;
+
+       bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR);
+       bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR);
+
+       if (bmcr & BMCR_ANENABLE) {
+               if (!(bmsr & BMSR_ANEGCOMPLETE))
+                       return;
+
+               lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA);
+
+               if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF))
+                       speed = SPEED_100;
+               else
+                       speed = SPEED_10;
+
+               if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL))
+                       duplex = DUPLEX_FULL;
+               else
+                       duplex = DUPLEX_HALF;
+
+       } else {
+               speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+               duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+       }
+
+       update_linkspeed_register(dev, speed, duplex);
+
+       dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed,
+                       (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+       ether->linkflag = 0x01;
+
+       netif_carrier_on(dev);
+}
+
+static void w90p910_check_link(unsigned long dev_id)
+{
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       update_linkspeed(dev);
+       mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
+}
+
+static void w90p910_write_cam(struct net_device *dev,
+                               unsigned int x, unsigned char *pval)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int msw, lsw;
+
+       msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
+
+       lsw = (pval[4] << 24) | (pval[5] << 16);
+
+       __raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE);
+       __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
+}
+
+static void w90p910_init_desc(struct net_device *dev)
+{
+       struct w90p910_ether *ether;
+       struct w90p910_txbd  *tdesc, *tdesc_phys;
+       struct w90p910_rxbd  *rdesc, *rdesc_phys;
+       unsigned int i, j;
+
+       ether = netdev_priv(dev);
+
+       ether->tdesc = (struct tran_pdesc *)
+                       dma_alloc_coherent(NULL, sizeof(struct tran_pdesc),
+                               (dma_addr_t *) &ether->tdesc_phys, GFP_KERNEL);
+
+       ether->rdesc = (struct recv_pdesc *)
+                       dma_alloc_coherent(NULL, sizeof(struct recv_pdesc),
+                               (dma_addr_t *) &ether->rdesc_phys, GFP_KERNEL);
+
+       for (i = 0; i < TX_DESC_SIZE; i++) {
+               tdesc = &(ether->tdesc->desclist[i]);
+
+               j = ((i + 1) / TX_DESC_SIZE);
+
+               if (j != 0) {
+                       tdesc_phys = &(ether->tdesc_phys->desclist[0]);
+                       ether->start_tx_ptr = (unsigned int)tdesc_phys;
+                       tdesc->next = (unsigned int)ether->start_tx_ptr;
+               } else {
+                       tdesc_phys = &(ether->tdesc_phys->desclist[i+1]);
+                       tdesc->next = (unsigned int)tdesc_phys;
+               }
+
+               tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i];
+               tdesc->sl = 0;
+               tdesc->mode = 0;
+       }
+
+       for (i = 0; i < RX_DESC_SIZE; i++) {
+               rdesc = &(ether->rdesc->desclist[i]);
+
+               j = ((i + 1) / RX_DESC_SIZE);
+
+               if (j != 0) {
+                       rdesc_phys = &(ether->rdesc_phys->desclist[0]);
+                       ether->start_rx_ptr = (unsigned int)rdesc_phys;
+                       rdesc->next = (unsigned int)ether->start_rx_ptr;
+               } else {
+                       rdesc_phys = &(ether->rdesc_phys->desclist[i+1]);
+                       rdesc->next = (unsigned int)rdesc_phys;
+               }
+
+               rdesc->sl = RX_OWEN_DMA;
+               rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i];
+         }
+}
+
+static void w90p910_set_fifo_threshold(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = TXTHD | BLENGTH;
+       __raw_writel(val, ether->reg + REG_FFTCR);
+}
+
+static void w90p910_return_default_idle(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = __raw_readl(ether->reg + REG_MCMDR);
+       val |= SWR;
+       __raw_writel(val, ether->reg + REG_MCMDR);
+}
+
+static void w90p910_trigger_rx(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       __raw_writel(ENSTART, ether->reg + REG_RSDR);
+}
+
+static void w90p910_trigger_tx(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       __raw_writel(ENSTART, ether->reg + REG_TSDR);
+}
+
+static void w90p910_enable_mac_interrupt(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP;
+       val |= ENTXBERR | ENRXBERR | ENTXABT;
+
+       __raw_writel(val, ether->reg + REG_MIEN);
+}
+
+static void w90p910_get_and_clear_int(struct net_device *dev,
+                                                       unsigned int *val)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       *val = __raw_readl(ether->reg + REG_MISTA);
+       __raw_writel(*val, ether->reg + REG_MISTA);
+}
+
+static void w90p910_set_global_maccmd(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = __raw_readl(ether->reg + REG_MCMDR);
+       val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC;
+       __raw_writel(val, ether->reg + REG_MCMDR);
+}
+
+static void w90p910_enable_cam(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       w90p910_write_cam(dev, CAM0, dev->dev_addr);
+
+       val = __raw_readl(ether->reg + REG_CAMEN);
+       val |= CAM0EN;
+       __raw_writel(val, ether->reg + REG_CAMEN);
+}
+
+static void w90p910_enable_cam_command(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP;
+       __raw_writel(val, ether->reg + REG_CAMCMR);
+}
+
+static void w90p910_enable_tx(struct net_device *dev, unsigned int enable)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = __raw_readl(ether->reg + REG_MCMDR);
+
+       if (enable)
+               val |= MCMDR_TXON;
+       else
+               val &= ~MCMDR_TXON;
+
+       __raw_writel(val, ether->reg + REG_MCMDR);
+}
+
+static void w90p910_enable_rx(struct net_device *dev, unsigned int enable)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       unsigned int val;
+
+       val = __raw_readl(ether->reg + REG_MCMDR);
+
+       if (enable)
+               val |= MCMDR_RXON;
+       else
+               val &= ~MCMDR_RXON;
+
+       __raw_writel(val, ether->reg + REG_MCMDR);
+}
+
+static void w90p910_set_curdest(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       __raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA);
+       __raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA);
+}
+
+static void w90p910_reset_mac(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       spin_lock(&ether->lock);
+
+       w90p910_enable_tx(dev, 0);
+       w90p910_enable_rx(dev, 0);
+       w90p910_set_fifo_threshold(dev);
+       w90p910_return_default_idle(dev);
+
+       if (!netif_queue_stopped(dev))
+               netif_stop_queue(dev);
+
+       w90p910_init_desc(dev);
+
+       dev->trans_start = jiffies;
+       ether->cur_tx = 0x0;
+       ether->finish_tx = 0x0;
+       ether->cur_rx = 0x0;
+
+       w90p910_set_curdest(dev);
+       w90p910_enable_cam(dev);
+       w90p910_enable_cam_command(dev);
+       w90p910_enable_mac_interrupt(dev);
+       w90p910_enable_tx(dev, 1);
+       w90p910_enable_rx(dev, 1);
+       w90p910_trigger_tx(dev);
+       w90p910_trigger_rx(dev);
+
+       dev->trans_start = jiffies;
+
+       if (netif_queue_stopped(dev))
+               netif_wake_queue(dev);
+
+       spin_unlock(&ether->lock);
+}
+
+static void w90p910_mdio_write(struct net_device *dev,
+                                       int phy_id, int reg, int data)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       struct platform_device *pdev;
+       unsigned int val, i;
+
+       pdev = ether->pdev;
+
+       __raw_writel(data, ether->reg + REG_MIID);
+
+       val = (phy_id << 0x08) | reg;
+       val |= PHYBUSY | PHYWR | MDCCR_VAL;
+       __raw_writel(val, ether->reg + REG_MIIDA);
+
+       for (i = 0; i < DELAY; i++) {
+               if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
+                       break;
+       }
+
+       if (i == DELAY)
+               dev_warn(&pdev->dev, "mdio write timed out\n");
+}
+
+static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       struct platform_device *pdev;
+       unsigned int val, i, data;
+
+       pdev = ether->pdev;
+
+       val = (phy_id << 0x08) | reg;
+       val |= PHYBUSY | MDCCR_VAL;
+       __raw_writel(val, ether->reg + REG_MIIDA);
+
+       for (i = 0; i < DELAY; i++) {
+               if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
+                       break;
+       }
+
+       if (i == DELAY) {
+               dev_warn(&pdev->dev, "mdio read timed out\n");
+               data = 0xffff;
+       } else {
+               data = __raw_readl(ether->reg + REG_MIID);
+       }
+
+       return data;
+}
+
+static int set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr *address = addr;
+
+       if (!is_valid_ether_addr(address->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+       w90p910_write_cam(dev, CAM0, dev->dev_addr);
+
+       return 0;
+}
+
+static int w90p910_ether_close(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd),
+                               ether->rdesc, (dma_addr_t)ether->rdesc_phys);
+       dma_free_writecombine(NULL, sizeof(struct w90p910_txbd),
+                               ether->tdesc, (dma_addr_t)ether->tdesc_phys);
+
+       netif_stop_queue(dev);
+
+       del_timer_sync(&ether->check_timer);
+       clk_disable(ether->rmiiclk);
+       clk_disable(ether->clk);
+
+       free_irq(ether->txirq, dev);
+       free_irq(ether->rxirq, dev);
+
+       return 0;
+}
+
+static struct net_device_stats *w90p910_ether_stats(struct net_device *dev)
+{
+       struct w90p910_ether *ether;
+
+       ether = netdev_priv(dev);
+
+       return &ether->stats;
+}
+
+static int w90p910_send_frame(struct net_device *dev,
+                                       unsigned char *data, int length)
+{
+       struct w90p910_ether *ether;
+       struct w90p910_txbd *txbd;
+       struct platform_device *pdev;
+       unsigned char *buffer;
+
+       ether = netdev_priv(dev);
+       pdev = ether->pdev;
+
+       txbd = &ether->tdesc->desclist[ether->cur_tx];
+       buffer = ether->tdesc->tran_buf[ether->cur_tx];
+       if (length > 1514) {
+               dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
+               length = 1514;
+       }
+
+       txbd->sl = length & 0xFFFF;
+
+       memcpy(buffer, data, length);
+
+       txbd->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
+
+       w90p910_enable_tx(dev, 1);
+
+       w90p910_trigger_tx(dev);
+
+       ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE;
+       txbd = &ether->tdesc->desclist[ether->cur_tx];
+
+       dev->trans_start = jiffies;
+
+       if (txbd->mode & TX_OWEN_DMA)
+               netif_stop_queue(dev);
+
+       return 0;
+}
+
+static int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       if (!(w90p910_send_frame(dev, skb->data, skb->len))) {
+               ether->skb = skb;
+               dev_kfree_skb_irq(skb);
+               return 0;
+       }
+       return -1;
+}
+
+static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
+{
+       struct w90p910_ether *ether;
+       struct w90p910_txbd  *txbd;
+       struct platform_device *pdev;
+       struct tran_pdesc *tran_pdesc;
+       struct net_device *dev;
+       unsigned int cur_entry, entry, status;
+
+       dev = (struct net_device *)dev_id;
+       ether = netdev_priv(dev);
+       pdev = ether->pdev;
+
+       spin_lock(&ether->lock);
+
+       w90p910_get_and_clear_int(dev, &status);
+
+       cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
+
+       tran_pdesc = ether->tdesc_phys;
+       entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+
+       while (entry != cur_entry) {
+               txbd = &ether->tdesc->desclist[ether->finish_tx];
+
+               ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE;
+
+               if (txbd->sl & TXDS_TXCP) {
+                       ether->stats.tx_packets++;
+                       ether->stats.tx_bytes += txbd->sl & 0xFFFF;
+               } else {
+                       ether->stats.tx_errors++;
+               }
+
+               txbd->sl = 0x0;
+               txbd->mode = 0x0;
+
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+
+               entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+       }
+
+       if (status & MISTA_EXDEF) {
+               dev_err(&pdev->dev, "emc defer exceed interrupt\n");
+       } else if (status & MISTA_TXBERR) {
+                       dev_err(&pdev->dev, "emc bus error interrupt\n");
+                       w90p910_reset_mac(dev);
+               } else if (status & MISTA_TDU) {
+                               if (netif_queue_stopped(dev))
+                                       netif_wake_queue(dev);
+                       }
+
+       spin_unlock(&ether->lock);
+
+       return IRQ_HANDLED;
+}
+
+static void netdev_rx(struct net_device *dev)
+{
+       struct w90p910_ether *ether;
+       struct w90p910_rxbd *rxbd;
+       struct platform_device *pdev;
+       struct recv_pdesc *rdesc_phys;
+       struct sk_buff *skb;
+       unsigned char *data;
+       unsigned int length, status, val, entry;
+
+       ether = netdev_priv(dev);
+       pdev = ether->pdev;
+       rdesc_phys = ether->rdesc_phys;
+
+       rxbd = &ether->rdesc->desclist[ether->cur_rx];
+
+       do {
+               val = __raw_readl(ether->reg + REG_CRXDSA);
+               entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx];
+
+               if (val == entry)
+                       break;
+
+               status = rxbd->sl;
+               length = status & 0xFFFF;
+
+               if (status & RXDS_RXGD) {
+                       data = ether->rdesc->recv_buf[ether->cur_rx];
+                       skb = dev_alloc_skb(length+2);
+                       if (!skb) {
+                               dev_err(&pdev->dev, "get skb buffer error\n");
+                               ether->stats.rx_dropped++;
+                               return;
+                       }
+
+                       skb->dev = dev;
+                       skb_reserve(skb, 2);
+                       skb_put(skb, length);
+                       skb_copy_to_linear_data(skb, data, length);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       ether->stats.rx_packets++;
+                       ether->stats.rx_bytes += length;
+                       netif_rx(skb);
+               } else {
+                       ether->stats.rx_errors++;
+
+                       if (status & RXDS_RP) {
+                               dev_err(&pdev->dev, "rx runt err\n");
+                               ether->stats.rx_length_errors++;
+                       } else if (status & RXDS_CRCE) {
+                                       dev_err(&pdev->dev, "rx crc err\n");
+                                       ether->stats.rx_crc_errors++;
+                               }
+
+                       if (status & RXDS_ALIE) {
+                               dev_err(&pdev->dev, "rx aligment err\n");
+                               ether->stats.rx_frame_errors++;
+                       } else if (status & RXDS_PTLE) {
+                                       dev_err(&pdev->dev, "rx longer err\n");
+                                       ether->stats.rx_over_errors++;
+                               }
+                       }
+
+               rxbd->sl = RX_OWEN_DMA;
+               rxbd->reserved = 0x0;
+               ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE;
+               rxbd = &ether->rdesc->desclist[ether->cur_rx];
+
+               dev->last_rx = jiffies;
+       } while (1);
+}
+
+static irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev;
+       struct w90p910_ether  *ether;
+       struct platform_device *pdev;
+       unsigned int status;
+
+       dev = (struct net_device *)dev_id;
+       ether = netdev_priv(dev);
+       pdev = ether->pdev;
+
+       spin_lock(&ether->lock);
+
+       w90p910_get_and_clear_int(dev, &status);
+
+       if (status & MISTA_RDU) {
+               netdev_rx(dev);
+
+               w90p910_trigger_rx(dev);
+
+               spin_unlock(&ether->lock);
+               return IRQ_HANDLED;
+       } else if (status & MISTA_RXBERR) {
+                       dev_err(&pdev->dev, "emc rx bus error\n");
+                       w90p910_reset_mac(dev);
+               }
+
+       netdev_rx(dev);
+       spin_unlock(&ether->lock);
+       return IRQ_HANDLED;
+}
+
+static int w90p910_ether_open(struct net_device *dev)
+{
+       struct w90p910_ether *ether;
+       struct platform_device *pdev;
+
+       ether = netdev_priv(dev);
+       pdev = ether->pdev;
+
+       w90p910_reset_mac(dev);
+       w90p910_set_fifo_threshold(dev);
+       w90p910_set_curdest(dev);
+       w90p910_enable_cam(dev);
+       w90p910_enable_cam_command(dev);
+       w90p910_enable_mac_interrupt(dev);
+       w90p910_set_global_maccmd(dev);
+       w90p910_enable_rx(dev, 1);
+
+       ether->rx_packets = 0x0;
+       ether->rx_bytes = 0x0;
+
+       if (request_irq(ether->txirq, w90p910_tx_interrupt,
+                                               0x0, pdev->name, dev)) {
+               dev_err(&pdev->dev, "register irq tx failed\n");
+               return -EAGAIN;
+       }
+
+       if (request_irq(ether->rxirq, w90p910_rx_interrupt,
+                                               0x0, pdev->name, dev)) {
+               dev_err(&pdev->dev, "register irq rx failed\n");
+               return -EAGAIN;
+       }
+
+       mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
+       netif_start_queue(dev);
+       w90p910_trigger_rx(dev);
+
+       dev_info(&pdev->dev, "%s is OPENED\n", dev->name);
+
+       return 0;
+}
+
+static void w90p910_ether_set_multicast_list(struct net_device *dev)
+{
+       struct w90p910_ether *ether;
+       unsigned int rx_mode;
+
+       ether = netdev_priv(dev);
+
+       if (dev->flags & IFF_PROMISC)
+               rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+       else if ((dev->flags & IFF_ALLMULTI) || dev->mc_list)
+                       rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+               else
+                               rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
+       __raw_writel(rx_mode, ether->reg + REG_CAMCMR);
+}
+
+static int w90p910_ether_ioctl(struct net_device *dev,
+                                               struct ifreq *ifr, int cmd)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       struct mii_ioctl_data *data = if_mii(ifr);
+
+       return generic_mii_ioctl(&ether->mii, data, cmd, NULL);
+}
+
+static void w90p910_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_MODULE_NAME);
+       strcpy(info->version, DRV_MODULE_VERSION);
+}
+
+static int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       return mii_ethtool_gset(&ether->mii, cmd);
+}
+
+static int w90p910_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       return mii_ethtool_sset(&ether->mii, cmd);
+}
+
+static int w90p910_nway_reset(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       return mii_nway_restart(&ether->mii);
+}
+
+static u32 w90p910_get_link(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       return mii_link_ok(&ether->mii);
+}
+
+static const struct ethtool_ops w90p910_ether_ethtool_ops = {
+       .get_settings   = w90p910_get_settings,
+       .set_settings   = w90p910_set_settings,
+       .get_drvinfo    = w90p910_get_drvinfo,
+       .nway_reset     = w90p910_nway_reset,
+       .get_link       = w90p910_get_link,
+};
+
+static const struct net_device_ops w90p910_ether_netdev_ops = {
+       .ndo_open               = w90p910_ether_open,
+       .ndo_stop               = w90p910_ether_close,
+       .ndo_start_xmit         = w90p910_ether_start_xmit,
+       .ndo_get_stats          = w90p910_ether_stats,
+       .ndo_set_multicast_list = w90p910_ether_set_multicast_list,
+       .ndo_set_mac_address    = set_mac_address,
+       .ndo_do_ioctl           = w90p910_ether_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+};
+
+static void __init get_mac_address(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+       struct platform_device *pdev;
+       char addr[6];
+
+       pdev = ether->pdev;
+
+       addr[0] = 0x00;
+       addr[1] = 0x02;
+       addr[2] = 0xac;
+       addr[3] = 0x55;
+       addr[4] = 0x88;
+       addr[5] = 0xa8;
+
+       if (is_valid_ether_addr(addr))
+               memcpy(dev->dev_addr, &addr, 0x06);
+       else
+               dev_err(&pdev->dev, "invalid mac address\n");
+}
+
+static int w90p910_ether_setup(struct net_device *dev)
+{
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       ether_setup(dev);
+       dev->netdev_ops = &w90p910_ether_netdev_ops;
+       dev->ethtool_ops = &w90p910_ether_ethtool_ops;
+
+       dev->tx_queue_len = 16;
+       dev->dma = 0x0;
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       get_mac_address(dev);
+
+       spin_lock_init(&ether->lock);
+
+       ether->cur_tx = 0x0;
+       ether->cur_rx = 0x0;
+       ether->finish_tx = 0x0;
+       ether->linkflag = 0x0;
+       ether->mii.phy_id = 0x01;
+       ether->mii.phy_id_mask = 0x1f;
+       ether->mii.reg_num_mask = 0x1f;
+       ether->mii.dev = dev;
+       ether->mii.mdio_read = w90p910_mdio_read;
+       ether->mii.mdio_write = w90p910_mdio_write;
+
+       setup_timer(&ether->check_timer, w90p910_check_link,
+                                               (unsigned long)dev);
+
+       return 0;
+}
+
+static int __devinit w90p910_ether_probe(struct platform_device *pdev)
+{
+       struct w90p910_ether *ether;
+       struct net_device *dev;
+       struct resource *res;
+       int error;
+
+       dev = alloc_etherdev(sizeof(struct w90p910_ether));
+       if (!dev)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               error = -ENXIO;
+               goto failed_free;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               error = -EBUSY;
+               goto failed_free;
+       }
+
+       ether = netdev_priv(dev);
+
+       ether->reg = ioremap(res->start, resource_size(res));
+       if (ether->reg == NULL) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENXIO;
+               goto failed_free_mem;
+       }
+
+       ether->txirq = platform_get_irq(pdev, 0);
+       if (ether->txirq < 0) {
+               dev_err(&pdev->dev, "failed to get ether tx irq\n");
+               error = -ENXIO;
+               goto failed_free_io;
+       }
+
+       ether->rxirq = platform_get_irq(pdev, 1);
+       if (ether->rxirq < 0) {
+               dev_err(&pdev->dev, "failed to get ether rx irq\n");
+               error = -ENXIO;
+               goto failed_free_txirq;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       ether->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ether->clk)) {
+               dev_err(&pdev->dev, "failed to get ether clock\n");
+               error = PTR_ERR(ether->clk);
+               goto failed_free_rxirq;
+       }
+
+       ether->rmiiclk = clk_get(&pdev->dev, "RMII");
+       if (IS_ERR(ether->rmiiclk)) {
+               dev_err(&pdev->dev, "failed to get ether clock\n");
+               error = PTR_ERR(ether->rmiiclk);
+               goto failed_put_clk;
+       }
+
+       ether->pdev = pdev;
+
+       w90p910_ether_setup(dev);
+
+       error = register_netdev(dev);
+       if (error != 0) {
+               dev_err(&pdev->dev, "Regiter EMC w90p910 FAILED\n");
+               error = -ENODEV;
+               goto failed_put_rmiiclk;
+       }
+
+       return 0;
+failed_put_rmiiclk:
+       clk_put(ether->rmiiclk);
+failed_put_clk:
+       clk_put(ether->clk);
+failed_free_rxirq:
+       free_irq(ether->rxirq, pdev);
+       platform_set_drvdata(pdev, NULL);
+failed_free_txirq:
+       free_irq(ether->txirq, pdev);
+failed_free_io:
+       iounmap(ether->reg);
+failed_free_mem:
+       release_mem_region(res->start, resource_size(res));
+failed_free:
+       free_netdev(dev);
+       return error;
+}
+
+static int __devexit w90p910_ether_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct w90p910_ether *ether = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       clk_put(ether->rmiiclk);
+       clk_put(ether->clk);
+       del_timer_sync(&ether->check_timer);
+       platform_set_drvdata(pdev, NULL);
+       free_netdev(dev);
+       return 0;
+}
+
+static struct platform_driver w90p910_ether_driver = {
+       .probe          = w90p910_ether_probe,
+       .remove         = __devexit_p(w90p910_ether_remove),
+       .driver         = {
+               .name   = "w90p910-emc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init w90p910_ether_init(void)
+{
+       return platform_driver_register(&w90p910_ether_driver);
+}
+
+static void __exit w90p910_ether_exit(void)
+{
+       platform_driver_unregister(&w90p910_ether_driver);
+}
+
+module_init(w90p910_ether_init);
+module_exit(w90p910_ether_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910 MAC driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:w90p910-emc");
+
index 18b566ad4fd17cedda3deff1fa2fefc45aa262a9..cf30e278f182f0a47e8b2770513994f2b9af77e1 100644 (file)
@@ -318,7 +318,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
                                pos3 = mca_read_stored_pos( slot, 3 );
                                pos4 = mca_read_stored_pos( slot, 4 );
 
-                               for (l_i = 0; l_i < 0x09; l_i++)
+                               for (l_i = 0; l_i < 8; l_i++)
                                        if (( pos3 & 0x07) == at1700_ioaddr_pattern[l_i])
                                                break;
                                ioaddr = at1700_mca_probe_list[l_i];
index e1658ef3fcdf04f0e75f71af8ddfae7e0113476a..2a1120ad2e74a4da9bf7186a0e7359d96a7e4ed3 100644 (file)
@@ -188,14 +188,14 @@ struct atl1c_tpd_ext_desc {
 #define RRS_HDS_TYPE_DATA      2
 
 #define RRS_IS_NO_HDS_TYPE(flag) \
-       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0)
+       ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == 0)
 
 #define RRS_IS_HDS_HEAD(flag) \
-       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+       ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == \
                        RRS_HDS_TYPE_HEAD)
 
 #define RRS_IS_HDS_DATA(flag) \
-       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+       ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == \
                        RRS_HDS_TYPE_DATA)
 
 /* rrs word 3 bit 0:31 */
@@ -245,7 +245,7 @@ struct atl1c_tpd_ext_desc {
 #define RRS_PACKET_TYPE_802_3          1
 #define RRS_PACKET_TYPE_ETH    0
 #define RRS_PACKET_IS_ETH(word) \
-       (((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \
+       ((((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK) == \
                        RRS_PACKET_TYPE_ETH)
 #define RRS_RXD_IS_VALID(word) \
        ((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1)
index cd547a205fb96d9d9a71f37cfbc57286686f31d2..a383122679de029b4e33a652d7007d071339cf3e 100644 (file)
@@ -1689,7 +1689,7 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
                if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
                        rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) &
                                RRS_RX_RFD_CNT_MASK;
-                       if (unlikely(rfd_num) != 1)
+                       if (unlikely(rfd_num != 1))
                                /* TODO support mul rfd*/
                                if (netif_msg_rx_err(adapter))
                                        dev_warn(&pdev->dev,
index c734b1983ec14667bc2debd4d5eec05b4f66369d..204db961029e798e74a8dc990d7b086207c0771c 100644 (file)
@@ -2071,7 +2071,7 @@ static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
                return -EOPNOTSUPP;
 
-       if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST))
+       if (wol->wolopts & (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
                return -EOPNOTSUPP;
 
        /* these settings will always override what we currently have */
index c43f6a119295097ac2c44d1040b38ae39502e1b8..dea3155688bbc570eaa6ba52f94832efe8170f80 100644 (file)
@@ -667,7 +667,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct be_rx_page_info *page_info;
        u16 rxq_idx, i, num_rcvd, j;
-       u32 pktsize, hdr_len, curr_frag_len;
+       u32 pktsize, hdr_len, curr_frag_len, size;
        u8 *start;
 
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -708,12 +708,13 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        }
 
        /* More frags present for this completion */
-       pktsize -= curr_frag_len; /* account for above copied frag */
+       size = pktsize;
        for (i = 1, j = 0; i < num_rcvd; i++) {
+               size -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
                page_info = get_rx_page_info(adapter, rxq_idx);
 
-               curr_frag_len = min(pktsize, rx_frag_size);
+               curr_frag_len = min(size, rx_frag_size);
 
                /* Coalesce all frags from the same physical page in one slot */
                if (page_info->page_offset == 0) {
@@ -731,7 +732,6 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
                skb_shinfo(skb)->frags[j].size += curr_frag_len;
                skb->len += curr_frag_len;
                skb->data_len += curr_frag_len;
-               pktsize -= curr_frag_len;
 
                memset(page_info, 0, sizeof(*page_info));
        }
index a76315dc77678e4009c0401b8f1a5afee4bc1859..206144f2470f388588e40cc1638f2fa3027608b5 100644 (file)
@@ -431,7 +431,7 @@ bmac_init_phy(struct net_device *dev)
                        printk(KERN_DEBUG);
                printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr));
        }
-       print(KERN_CONT "\n");
+       printk(KERN_CONT "\n");
 
        if (bp->is_bmac_plus) {
                unsigned int capable, ctrl;
index ed648acef7cffef16ee31923562b0a8b9c9ed731..2ee581a2cdec7f6210d0f95a71e996ec788299c5 100644 (file)
@@ -4212,13 +4212,14 @@ static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
 u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
                              u8 *version, u16 len)
 {
-       struct bnx2x *bp = params->bp;
+       struct bnx2x *bp;
        u32 ext_phy_type = 0;
        u32 spirom_ver = 0;
        u8 status = 0 ;
 
        if (version == NULL || params == NULL)
                return -EINVAL;
+       bp = params->bp;
 
        spirom_ver = REG_RD(bp, params->shmem_base +
                   offsetof(struct shmem_region,
index d927f71af8a31b9096b4ded0f9b18ab47a847116..aa1be1feceedad372f01d082904b66470f55273e 100644 (file)
@@ -1459,8 +1459,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * 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);
+               if (bond_dev->type != slave_dev->type) {
+                       dev_close(bond_dev);
+                       pr_debug("%s: change device type from %d to %d\n",
+                               bond_dev->name, bond_dev->type, slave_dev->type);
+                       if (slave_dev->type != ARPHRD_ETHER)
+                               bond_setup_by_slave(bond_dev, slave_dev);
+                       else
+                               ether_setup(bond_dev);
+                       dev_open(bond_dev);
+               }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err(DRV_NAME ": %s ether type (%d) is different "
                        "from other slaves (%d), can not enslave it.\n",
index 574daddc21bfb02817fb3b49cfe5dec624936f8e..9e4283aff828d9adc1f03db2276b38add2b9a31d 100644 (file)
@@ -346,7 +346,7 @@ void can_restart(unsigned long data)
        skb = dev_alloc_skb(sizeof(struct can_frame));
        if (skb == NULL) {
                err = -ENOMEM;
-               goto out;
+               goto restart;
        }
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
@@ -361,13 +361,13 @@ void can_restart(unsigned long data)
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
 
+restart:
        dev_dbg(dev->dev.parent, "restarted\n");
        priv->can_stats.restarts++;
 
        /* Now restart the device */
        err = priv->do_set_mode(dev, CAN_MODE_START);
 
-out:
        netif_carrier_on(dev);
        if (err)
                dev_err(dev->dev.parent, "Error %d during restart", err);
@@ -473,6 +473,10 @@ int open_candev(struct net_device *dev)
                return -EINVAL;
        }
 
+       /* Switch carrier on if device was stopped while in bus-off state */
+       if (!netif_carrier_ok(dev))
+               netif_carrier_on(dev);
+
        setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
 
        return 0;
index 571f133a8fec5a94bf1493defb66f56c56520681..08ebee79d8a6a5e5d850922654b2529a34200d98 100644 (file)
@@ -63,7 +63,6 @@
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
-#include <linux/can/dev.h>
 
 #include "sja1000.h"
 
index 4d1515f45ba24657777370c151eb26e475f9b85e..4869d77cbe91dc9fde5cee6b82babc8f50517ff7 100644 (file)
@@ -227,7 +227,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
        }
 
        rcu_read_lock();
-       ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
+       ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
        if (ulp_ops)
                ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len);
        rcu_read_unlock();
@@ -319,6 +319,20 @@ static int cnic_abort_prep(struct cnic_sock *csk)
        return 0;
 }
 
+static void cnic_uio_stop(void)
+{
+       struct cnic_dev *dev;
+
+       read_lock(&cnic_dev_lock);
+       list_for_each_entry(dev, &cnic_dev_list, list) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               if (cp->cnic_uinfo)
+                       cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+       }
+       read_unlock(&cnic_dev_lock);
+}
+
 int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
 {
        struct cnic_dev *dev;
@@ -390,6 +404,9 @@ int cnic_unregister_driver(int ulp_type)
        }
        read_unlock(&cnic_dev_lock);
 
+       if (ulp_type == CNIC_ULP_ISCSI)
+               cnic_uio_stop();
+
        rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
 
        mutex_unlock(&cnic_lock);
@@ -632,7 +649,6 @@ static void cnic_free_resc(struct cnic_dev *dev)
        int i = 0;
 
        if (cp->cnic_uinfo) {
-               cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
                while (cp->uio_dev != -1 && i < 15) {
                        msleep(100);
                        i++;
@@ -1057,6 +1073,9 @@ static void cnic_ulp_stop(struct cnic_dev *dev)
        struct cnic_local *cp = dev->cnic_priv;
        int if_type;
 
+       if (cp->cnic_uinfo)
+               cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+
        rcu_read_lock();
        for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
                struct cnic_ulp_ops *ulp_ops;
index 3eee666a9cd26773fa4712704cf7066ec7f0cbc5..55445f980f9c975596d41b3a9e9a0887155f061b 100644 (file)
@@ -1524,6 +1524,7 @@ static void net_timeout(struct net_device *dev)
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_local *lp = netdev_priv(dev);
+       unsigned long flags;
 
        if (net_debug > 3) {
                printk("%s: sent %d byte packet of type %x\n",
@@ -1535,7 +1536,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                   ask the chip to start transmitting before the
                   whole packet has been completely uploaded. */
 
-       spin_lock_irq(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        netif_stop_queue(dev);
 
        /* initiate a transmit sequence */
@@ -1549,13 +1550,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                 * we're waiting for TxOk, so return 1 and requeue this packet.
                 */
 
-               spin_unlock_irq(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                if (net_debug) printk("cs89x0: Tx buffer not free!\n");
                return NETDEV_TX_BUSY;
        }
        /* Write the contents of the packet */
        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-       spin_unlock_irq(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
index 538dda4422dca039b01715e8ca10892af4954ea1..fb5df5c6203e9541849fce56a52abfaedfbe7391 100644 (file)
@@ -642,8 +642,7 @@ static int setup_sge_qsets(struct adapter *adap)
                struct port_info *pi = netdev_priv(dev);
 
                pi->qs = &adap->sge.qs[pi->first_qset];
-               for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
-                    ++j, ++qset_idx) {
+               for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
                        set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
                        err = t3_sge_alloc_qset(adap, qset_idx, 1,
                                (adap->flags & USING_MSIX) ? qset_idx + 1 :
index 2df8fb0af701a0e081d8fee4820bb4047e2d6a6c..12fd446f9895036c6e7f099e0abc7517d9678f59 100644 (file)
@@ -1820,11 +1820,19 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        struct device *emac_dev = &priv->ndev->dev;
        struct sockaddr *sa = addr;
 
+       if (!is_valid_ether_addr(sa->sa_data))
+               return -EINVAL;
+
        /* Store mac addr in priv and rx channel and set it in EMAC hw */
        memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
-       memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
        memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
-       emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+
+       /* If the interface is down - rxch is NULL. */
+       /* MAC address is configured only after the interface is enabled. */
+       if (netif_running(ndev)) {
+               memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
+               emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+       }
 
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n",
index efa680f4b8ddceebf8ce166cc3d02409de533a5e..41b648a67fec34d071a5ee681b713e4cada6ee87 100644 (file)
@@ -1897,6 +1897,9 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
                        if (ioread8(&nic->csr->scb.status) & rus_no_res)
                                nic->ru_running = RU_SUSPENDED;
+               pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
+                                              sizeof(struct rfd),
+                                              PCI_DMA_BIDIRECTIONAL);
                return -ENODATA;
        }
 
index cc2ab6412c7382484073f405306a4a76775b59bd..4f70034853482ef8c51262892002756c22599ae2 100644 (file)
@@ -1784,7 +1784,7 @@ int __init init_module(void)
                printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
        }
 
-       for (i = 0; io[i] != -1 && i < MAX_EEPRO; i++) {
+       for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
                dev = alloc_etherdev(sizeof(struct eepro_local));
                if (!dev)
                        break;
index 147c4b088fb3c3467fa3b9027aa887067ccf8114..e8d46cc1bec2525ac014a727f7743dd77c108848 100644 (file)
@@ -3080,7 +3080,9 @@ static const struct net_device_ops ehea_netdev_ops = {
        .ndo_poll_controller    = ehea_netpoll,
 #endif
        .ndo_get_stats          = ehea_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_set_mac_address    = ehea_set_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_multicast_list = ehea_set_multicast_list,
        .ndo_change_mtu         = ehea_change_mtu,
        .ndo_vlan_rx_register   = ehea_vlan_rx_register,
index 053fb49820b9c27f0ed892d9be219b71f9a77400..160655d2458159c84ad1656554f853356ab6f98a 100644 (file)
@@ -584,7 +584,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
        if (np->flags == HAS_MII_XCVR) {
                int phy, phy_idx = 0;
 
-               for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
+               for (phy = 1; phy < 32 && phy_idx < ARRAY_SIZE(np->phys);
+                              phy++) {
                        int mii_status = mdio_read(dev, phy, 1);
 
                        if (mii_status != 0xffff && mii_status != 0x0000) {
@@ -1216,13 +1217,13 @@ static void fealnx_tx_timeout(struct net_device *dev)
        {
                printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(PR_CONT " %8.8x",
+                       printk(KERN_CONT " %8.8x",
                               (unsigned int) np->rx_ring[i].status);
                printk(KERN_CONT "\n");
                printk(KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(PR_CONT " %4.4x", np->tx_ring[i].status);
-               printk(PR_CONT "\n");
+                       printk(KERN_CONT " %4.4x", np->tx_ring[i].status);
+               printk(KERN_CONT "\n");
        }
 
        spin_lock_irqsave(&np->lock, flags);
index 0f19b743749bdf8b52783793276c36a247f3f928..d4b98074b1b787e481c3d13f6dd351494245ac11 100644 (file)
@@ -1642,6 +1642,7 @@ static const struct net_device_ops fec_netdev_ops = {
        .ndo_stop               = fec_enet_close,
        .ndo_start_xmit         = fec_enet_start_xmit,
        .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = fec_timeout,
        .ndo_set_mac_address    = fec_set_mac_address,
index 30b7dd671336b45434bdefff08c137da3ee8bf9a..cc47f3f057c7464b2f5096e7810bad46c9362cf7 100644 (file)
 
 #else
 
-#define FEC_ECNTRL;            0x000 /* Ethernet control reg */
-#define FEC_IEVENT;            0x004 /* Interrupt even reg */
-#define FEC_IMASK;             0x008 /* Interrupt mask reg */
-#define FEC_IVEC;              0x00c /* Interrupt vec status reg */
-#define FEC_R_DES_ACTIVE;      0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE;      0x01c /* Transmit descriptor reg */
+#define FEC_ECNTRL             0x000 /* Ethernet control reg */
+#define FEC_IEVENT             0x004 /* Interrupt even reg */
+#define FEC_IMASK              0x008 /* Interrupt mask reg */
+#define FEC_IVEC               0x00c /* Interrupt vec status reg */
+#define FEC_R_DES_ACTIVE       0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE       0x014 /* Transmit descriptor reg */
 #define FEC_MII_DATA           0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED          0x044 /* MII speed control reg */
 #define FEC_R_BOUND            0x08c /* FIFO receive bound reg */
index b892c3ad9a742de2957dd5b1a0c14be158d52b8c..2bc2d2b20644ba924f0031c512b9a8468cc46fa0 100644 (file)
@@ -754,17 +754,16 @@ static int fs_init_phy(struct net_device *dev)
        fep->oldlink = 0;
        fep->oldspeed = 0;
        fep->oldduplex = -1;
-       if(fep->fpi->phy_node)
-               phydev = of_phy_connect(dev, fep->fpi->phy_node,
-                                       &fs_adjust_link, 0,
-                                       PHY_INTERFACE_MODE_MII);
-       else {
-               printk("No phy bus ID specified in BSP code\n");
-               return -EINVAL;
+
+       phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0,
+                               PHY_INTERFACE_MODE_MII);
+       if (!phydev) {
+               phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link,
+                                                  PHY_INTERFACE_MODE_MII);
        }
-       if (IS_ERR(phydev)) {
-               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(phydev);
+       if (!phydev) {
+               dev_err(&dev->dev, "Could not attach to PHY\n");
+               return -ENODEV;
        }
 
        fep->phydev = phydev;
@@ -1005,6 +1004,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
                goto out_free_fpi;
        }
 
+       SET_NETDEV_DEV(ndev, &ofdev->dev);
        dev_set_drvdata(&ofdev->dev, ndev);
 
        fep = netdev_priv(ndev);
index 4ae1d259fced7d6525a6818a1c641db5d1cf3850..f8ffcbf0bc39551eac65f4f8cb969edf61908ee8 100644 (file)
@@ -156,6 +156,8 @@ static const struct net_device_ops gfar_netdev_ops = {
        .ndo_tx_timeout = gfar_timeout,
        .ndo_do_ioctl = gfar_ioctl,
        .ndo_vlan_rx_register = gfar_vlan_rx_register,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gfar_netpoll,
 #endif
@@ -262,15 +264,6 @@ static int gfar_of_init(struct net_device *dev)
                priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
 
        priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
-       if (!priv->phy_node) {
-               u32 *fixed_link;
-
-               fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
-               if (!fixed_link) {
-                       err = -ENODEV;
-                       goto err_out;
-               }
-       }
 
        /* Find the TBI PHY.  If it's not there, we don't support SGMII */
        priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -657,13 +650,14 @@ static int init_phy(struct net_device *dev)
 
        interface = gfar_get_interface(dev);
 
-       if (priv->phy_node) {
-               priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link,
-                                             0, interface);
-               if (!priv->phydev) {
-                       dev_err(&dev->dev, "error: Could not attach to PHY\n");
-                       return -ENODEV;
-               }
+       priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, 0,
+                                     interface);
+       if (!priv->phydev)
+               priv->phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+                                                        interface);
+       if (!priv->phydev) {
+               dev_err(&dev->dev, "could not attach to PHY\n");
+               return -ENODEV;
        }
 
        if (interface == PHY_INTERFACE_MODE_SGMII)
index 155160052c8bd5dc690c1bfe04b253654e739cab..981ab530e9aca771028a1a4f636a514fb19bf18c 100644 (file)
@@ -3,7 +3,7 @@
  *             devices like TTY. It interfaces between a raw TTY and the
  *             kernel's AX.25 protocol layers.
  *
- * Authors:    Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ * Authors:    Andreas Könsgen <ajk@comnets.uni-bremen.de>
  *              Ralf Baechle DL5RB <ralf@linux-mips.org>
  *
  * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
index 1d5379de6900f5558e8130b0e4c84b5e3e85f818..8d76cb89dbd61e6d252ed30fbe1bf211f5081732 100644 (file)
@@ -188,11 +188,12 @@ void rgmii_put_mdio(struct of_device *ofdev, int input)
 void rgmii_detach(struct of_device *ofdev, int input)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs __iomem *p = dev->base;
-
-       mutex_lock(&dev->lock);
+       struct rgmii_regs __iomem *p;
 
        BUG_ON(!dev || dev->users == 0);
+       p = dev->base;
+
+       mutex_lock(&dev->lock);
 
        RGMII_DBG(dev, "detach(%d)" NL, input);
 
index efd9be214885cbc4c5c5282df7072aee901beff9..ac28dd5a4fd137f7cd522bbcf20fb3338ecffc38 100644 (file)
@@ -190,6 +190,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                phy->ops.write_reg          = igb_write_phy_reg_igp;
        }
 
+       /* set lan id */
+       hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
+                      E1000_STATUS_FUNC_SHIFT;
+
        /* Set phy->phy_addr and phy->id. */
        ret_val = igb_get_phy_id_82575(hw);
        if (ret_val)
index be480292aba18f998baf33100a436736e72df1e1..adb09d32625df3c2b4a565324f17927ed2db033d 100644 (file)
@@ -127,14 +127,48 @@ static void igb_restore_vlan(struct igb_adapter *);
 static void igb_ping_all_vfs(struct igb_adapter *);
 static void igb_msg_task(struct igb_adapter *);
 static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
-static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
 static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
 static void igb_vmm_control(struct igb_adapter *);
-static inline void igb_set_vmolr(struct e1000_hw *, int);
-static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
 static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
 static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
 
+static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_VMOLR(vfn));
+       reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
+                   E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
+                   E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
+                   E1000_VMOLR_AUPE |   /* Accept untagged packets */
+                   E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+       wr32(E1000_VMOLR(vfn), reg_data);
+}
+
+static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
+                                 int vfn)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vmolr;
+
+       vmolr = rd32(E1000_VMOLR(vfn));
+       vmolr &= ~E1000_VMOLR_RLPML_MASK;
+       vmolr |= size | E1000_VMOLR_LPE;
+       wr32(E1000_VMOLR(vfn), vmolr);
+
+       return 0;
+}
+
+static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_RAH(entry));
+       reg_data &= ~E1000_RAH_POOL_MASK;
+       reg_data |= E1000_RAH_POOL_1 << pool;;
+       wr32(E1000_RAH(entry), reg_data);
+}
+
 #ifdef CONFIG_PM
 static int igb_suspend(struct pci_dev *, pm_message_t);
 static int igb_resume(struct pci_dev *);
@@ -5418,43 +5452,6 @@ static void igb_io_resume(struct pci_dev *pdev)
        igb_get_hw_control(adapter);
 }
 
-static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
-{
-       u32 reg_data;
-
-       reg_data = rd32(E1000_VMOLR(vfn));
-       reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
-                   E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
-                   E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
-                   E1000_VMOLR_AUPE |   /* Accept untagged packets */
-                   E1000_VMOLR_STRVLAN; /* Strip vlan tags */
-       wr32(E1000_VMOLR(vfn), reg_data);
-}
-
-static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
-                                 int vfn)
-{
-       struct e1000_hw *hw = &adapter->hw;
-       u32 vmolr;
-
-       vmolr = rd32(E1000_VMOLR(vfn));
-       vmolr &= ~E1000_VMOLR_RLPML_MASK;
-       vmolr |= size | E1000_VMOLR_LPE;
-       wr32(E1000_VMOLR(vfn), vmolr);
-
-       return 0;
-}
-
-static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
-{
-       u32 reg_data;
-
-       reg_data = rd32(E1000_RAH(entry));
-       reg_data &= ~E1000_RAH_POOL_MASK;
-       reg_data |= E1000_RAH_POOL_1 << pool;;
-       wr32(E1000_RAH(entry), reg_data);
-}
-
 static void igb_set_mc_list_pools(struct igb_adapter *adapter,
                                  int entry_count, u16 total_rar_filters)
 {
index d53aa9582137d241f0cdf22e092de488ec81efb9..20f9bc6266882eae0dae82707d9935f6bee1b8d4 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 
index 73585fd8f29fdaee4a4647e6cdebe986c396e5ff..d12377b843581c1947fd1bdb33b9e9fe6d6ca4e4 100644 (file)
@@ -430,7 +430,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * hardware interrupt handler.  Queue flow control is
         * thus managed under this lock as well.
         */
-       spin_lock_irq(&np->lock);
+       unsigned long flags;
+       spin_lock_irqsave(&np->lock, flags);
 
        add_to_tx_ring(np, skb, length);
        dev->trans_start = jiffies;
@@ -446,7 +447,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * is when the transmit statistics are updated.
         */
 
-       spin_unlock_irq(&np->lock);
+       spin_unlock_irqrestore(&np->lock, flags);
 #else
        /* This is the case for older hardware which takes
         * a single transmit buffer at a time, and it is
index cd22323cfd2276009b15bf0254bdcfbbafce00e5..1b12c7ba275fe9a60150a7a33933fbe4399cebde 100644 (file)
@@ -327,6 +327,7 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_IN_SFP_MOD_TASK              (u32)(1 << 25)
 #define IXGBE_FLAG_FDIR_HASH_CAPABLE            (u32)(1 << 26)
 #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE         (u32)(1 << 27)
+#define IXGBE_FLAG_FCOE_CAPABLE                 (u32)(1 << 28)
 #define IXGBE_FLAG_FCOE_ENABLED                 (u32)(1 << 29)
 
        u32 flags2;
index d56890f5c9d53f736c1ba58c5c1d73f5e2c131d2..1c7265732900643ce27365c23212613c9d674c8d 100644 (file)
@@ -106,8 +106,6 @@ static u8 ixgbe_dcbnl_get_state(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n");
-
        return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED);
 }
 
@@ -116,8 +114,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
        u8 err = 0;
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n");
-
        if (state > 0) {
                /* Turn on DCB */
                if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
@@ -138,7 +134,23 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                        adapter->hw.fc.requested_mode = ixgbe_fc_none;
                }
                adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+               if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+                       adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+                       adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+               }
                adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
+#ifdef IXGBE_FCOE
+               /* Turn on FCoE offload */
+               if ((adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) &&
+                   (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))) {
+                       adapter->flags |= IXGBE_FLAG_FCOE_ENABLED;
+                       adapter->ring_feature[RING_F_FCOE].indices =
+                               IXGBE_FCRETA_SIZE;
+                       netdev->features |= NETIF_F_FCOE_CRC;
+                       netdev->features |= NETIF_F_FSO;
+                       netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
+               }
+#endif /* IXGBE_FCOE */
                ixgbe_init_interrupt_scheme(adapter);
                if (netif_running(netdev))
                        netdev->netdev_ops->ndo_open(netdev);
@@ -154,6 +166,20 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                        adapter->dcb_cfg.pfc_mode_enable = false;
                        adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
                        adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
+                       if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+                               adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+#ifdef IXGBE_FCOE
+                       /* Turn off FCoE offload */
+                       if (adapter->flags & (IXGBE_FLAG_FCOE_CAPABLE |
+                            IXGBE_FLAG_FCOE_ENABLED)) {
+                               adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+                               adapter->ring_feature[RING_F_FCOE].indices = 0;
+                               netdev->features &= ~NETIF_F_FCOE_CRC;
+                               netdev->features &= ~NETIF_F_FSO;
+                               netdev->fcoe_ddp_xid = 0;
+                       }
+#endif /* IXGBE_FCOE */
                        ixgbe_init_interrupt_scheme(adapter);
                        if (netif_running(netdev))
                                netdev->netdev_ops->ndo_open(netdev);
@@ -169,6 +195,8 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        int i, j;
 
+       memset(perm_addr, 0xff, MAX_ADDR_LEN);
+
        for (i = 0; i < netdev->addr_len; i++)
                perm_addr[i] = adapter->hw.mac.perm_addr[i];
 
index a3061aacffd841f3eb27ef3092740e27906219b5..200454f30f6a75f75774de5bede171c963f2b6e7 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/pkt_sched.h>
 #include <linux/ipv6.h>
 #include <net/checksum.h>
 #include <net/ip6_checksum.h>
@@ -510,8 +511,11 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
  * @skb: skb currently being received and modified
  **/
 static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
-                                     u32 status_err, struct sk_buff *skb)
+                                    union ixgbe_adv_rx_desc *rx_desc,
+                                    struct sk_buff *skb)
 {
+       u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error);
+
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum disabled */
@@ -529,6 +533,16 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
                return;
 
        if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+               u16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+
+               /*
+                * 82599 errata, UDP frames with a 0 checksum can be marked as
+                * checksum errors.
+                */
+               if ((pkt_info & IXGBE_RXDADV_PKTTYPE_UDP) &&
+                   (adapter->hw.mac.type == ixgbe_mac_82599EB))
+                       return;
+
                adapter->hw_csum_rx_error++;
                return;
        }
@@ -802,7 +816,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                        goto next_desc;
                }
 
-               ixgbe_rx_checksum(adapter, staterr, skb);
+               ixgbe_rx_checksum(adapter, rx_desc, skb);
 
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
@@ -3130,7 +3144,11 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
 #endif
                if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
                        DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n");
-                       ixgbe_set_rss_queues(adapter);
+                       if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+                           (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+                               ixgbe_set_fdir_queues(adapter);
+                       else
+                               ixgbe_set_rss_queues(adapter);
                }
                /* adding FCoE rx rings to the end */
                f->mask = adapter->num_rx_queues;
@@ -3388,7 +3406,12 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
                }
 #endif /* CONFIG_IXGBE_DCB */
                if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
-                       ixgbe_cache_ring_rss(adapter);
+                       if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+                           (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+                               ixgbe_cache_ring_fdir(adapter);
+                       else
+                               ixgbe_cache_ring_rss(adapter);
+
                        fcoe_i = f->mask;
                }
                for (i = 0; i < f->indices; i++, fcoe_i++)
@@ -3797,8 +3820,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                adapter->atr_sample_rate = 20;
                adapter->fdir_pballoc = 0;
 #ifdef IXGBE_FCOE
-               adapter->flags |= IXGBE_FLAG_FCOE_ENABLED;
-               adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE;
+               adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
+               adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+               adapter->ring_feature[RING_F_FCOE].indices = 0;
 #endif /* IXGBE_FCOE */
        }
 
@@ -5116,9 +5140,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        int count = 0;
        unsigned int f;
 
-       r_idx = skb->queue_mapping;
-       tx_ring = &adapter->tx_ring[r_idx];
-
        if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
                tx_flags |= vlan_tx_tag_get(skb);
                if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
@@ -5128,11 +5149,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
        } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
-               tx_flags |= (skb->queue_mapping << 13);
-               tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
-               tx_flags |= IXGBE_TX_FLAGS_VLAN;
+               if (skb->priority != TC_PRIO_CONTROL) {
+                       tx_flags |= (skb->queue_mapping << 13);
+                       tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+                       tx_flags |= IXGBE_TX_FLAGS_VLAN;
+               } else {
+                       skb->queue_mapping =
+                               adapter->ring_feature[RING_F_DCB].indices-1;
+               }
        }
 
+       r_idx = skb->queue_mapping;
+       tx_ring = &adapter->tx_ring[r_idx];
+
        if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
            (skb->protocol == htons(ETH_P_FCOE)))
                tx_flags |= IXGBE_TX_FLAGS_FCOE;
@@ -5571,22 +5600,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 #endif
 
 #ifdef IXGBE_FCOE
-       if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
+       if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
                if (hw->mac.ops.get_device_caps) {
                        hw->mac.ops.get_device_caps(hw, &device_caps);
-                       if (!(device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)) {
-                               netdev->features |= NETIF_F_FCOE_CRC;
-                               netdev->features |= NETIF_F_FSO;
-                               netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
-                               DPRINTK(DRV, INFO, "FCoE enabled, "
-                                       "disabling Flow Director\n");
-                               adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
-                               adapter->flags &=
-                                       ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
-                               adapter->atr_sample_rate = 0;
-                       } else {
-                               adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
-                       }
+                       if (device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)
+                               adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
                }
        }
 #endif /* IXGBE_FCOE */
@@ -5635,7 +5653,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                adapter->wol = 0;
                break;
        }
-       device_init_wakeup(&adapter->pdev->dev, true);
        device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
        /* pick up the PCI bus settings for reporting later */
index d12106b47bf2a6cbd9130c9f5840a4322108f5d2..2f286091394d3241bc0bff2cef271ee79c141c00 100644 (file)
@@ -229,6 +229,7 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
        lp = netdev_priv(dev);
        lp->device = &pdev->dev;
        SET_NETDEV_DEV(dev, &pdev->dev);
+       platform_set_drvdata(pdev, dev);
 
        netdev_boot_setup_check(dev);
 
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
new file mode 100644 (file)
index 0000000..9a1dea6
--- /dev/null
@@ -0,0 +1,1322 @@
+/* drivers/net/ks8651.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *     http://www.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/cache.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+
+#include <linux/spi/spi.h>
+
+#include "ks8851.h"
+
+/**
+ * struct ks8851_rxctrl - KS8851 driver rx control
+ * @mchash: Multicast hash-table data.
+ * @rxcr1: KS_RXCR1 register setting
+ * @rxcr2: KS_RXCR2 register setting
+ *
+ * Representation of the settings needs to control the receive filtering
+ * such as the multicast hash-filter and the receive register settings. This
+ * is used to make the job of working out if the receive settings change and
+ * then issuing the new settings to the worker that will send the necessary
+ * commands.
+ */
+struct ks8851_rxctrl {
+       u16     mchash[4];
+       u16     rxcr1;
+       u16     rxcr2;
+};
+
+/**
+ * union ks8851_tx_hdr - tx header data
+ * @txb: The header as bytes
+ * @txw: The header as 16bit, little-endian words
+ *
+ * A dual representation of the tx header data to allow
+ * access to individual bytes, and to allow 16bit accesses
+ * with 16bit alignment.
+ */
+union ks8851_tx_hdr {
+       u8      txb[6];
+       __le16  txw[3];
+};
+
+/**
+ * struct ks8851_net - KS8851 driver private data
+ * @netdev: The network device we're bound to
+ * @spidev: The spi device we're bound to.
+ * @lock: Lock to ensure that the device is not accessed when busy.
+ * @statelock: Lock on this structure for tx list.
+ * @mii: The MII state information for the mii calls.
+ * @rxctrl: RX settings for @rxctrl_work.
+ * @tx_work: Work queue for tx packets
+ * @irq_work: Work queue for servicing interrupts
+ * @rxctrl_work: Work queue for updating RX mode and multicast lists
+ * @txq: Queue of packets for transmission.
+ * @spi_msg1: pre-setup SPI transfer with one message, @spi_xfer1.
+ * @spi_msg2: pre-setup SPI transfer with two messages, @spi_xfer2.
+ * @txh: Space for generating packet TX header in DMA-able data
+ * @rxd: Space for receiving SPI data, in DMA-able space.
+ * @txd: Space for transmitting SPI data, in DMA-able space.
+ * @msg_enable: The message flags controlling driver output (see ethtool).
+ * @fid: Incrementing frame id tag.
+ * @rc_ier: Cached copy of KS_IER.
+ * @rc_rxqcr: Cached copy of KS_RXQCR.
+ *
+ * The @lock ensures that the chip is protected when certain operations are
+ * in progress. When the read or write packet transfer is in progress, most
+ * of the chip registers are not ccessible until the transfer is finished and
+ * the DMA has been de-asserted.
+ *
+ * The @statelock is used to protect information in the structure which may
+ * need to be accessed via several sources, such as the network driver layer
+ * or one of the work queues.
+ *
+ * We align the buffers we may use for rx/tx to ensure that if the SPI driver
+ * wants to DMA map them, it will not have any problems with data the driver
+ * modifies.
+ */
+struct ks8851_net {
+       struct net_device       *netdev;
+       struct spi_device       *spidev;
+       struct mutex            lock;
+       spinlock_t              statelock;
+
+       union ks8851_tx_hdr     txh ____cacheline_aligned;
+       u8                      rxd[8];
+       u8                      txd[8];
+
+       u32                     msg_enable ____cacheline_aligned;
+       u16                     tx_space;
+       u8                      fid;
+
+       u16                     rc_ier;
+       u16                     rc_rxqcr;
+
+       struct mii_if_info      mii;
+       struct ks8851_rxctrl    rxctrl;
+
+       struct work_struct      tx_work;
+       struct work_struct      irq_work;
+       struct work_struct      rxctrl_work;
+
+       struct sk_buff_head     txq;
+
+       struct spi_message      spi_msg1;
+       struct spi_message      spi_msg2;
+       struct spi_transfer     spi_xfer1;
+       struct spi_transfer     spi_xfer2[2];
+};
+
+static int msg_enable;
+
+#define ks_info(_ks, _msg...) dev_info(&(_ks)->spidev->dev, _msg)
+#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->spidev->dev, _msg)
+#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->spidev->dev, _msg)
+#define ks_err(_ks, _msg...) dev_err(&(_ks)->spidev->dev, _msg)
+
+/* shift for byte-enable data */
+#define BYTE_EN(_x)    ((_x) << 2)
+
+/* turn register number and byte-enable mask into data for start of packet */
+#define MK_OP(_byteen, _reg) (BYTE_EN(_byteen) | (_reg)  << (8+2) | (_reg) >> 6)
+
+/* SPI register read/write calls.
+ *
+ * All these calls issue SPI transactions to access the chip's registers. They
+ * all require that the necessary lock is held to prevent accesses when the
+ * chip is busy transfering packet data (RX/TX FIFO accesses).
+ */
+
+/**
+ * ks8851_wrreg16 - write 16bit register value to chip
+ * @ks: The chip state
+ * @reg: The register address
+ * @val: The value to write
+ *
+ * Issue a write to put the value @val into the register specified in @reg.
+ */
+static void ks8851_wrreg16(struct ks8851_net *ks, unsigned reg, unsigned val)
+{
+       struct spi_transfer *xfer = &ks->spi_xfer1;
+       struct spi_message *msg = &ks->spi_msg1;
+       __le16 txb[2];
+       int ret;
+
+       txb[0] = cpu_to_le16(MK_OP(reg & 2 ? 0xC : 0x03, reg) | KS_SPIOP_WR);
+       txb[1] = cpu_to_le16(val);
+
+       xfer->tx_buf = txb;
+       xfer->rx_buf = NULL;
+       xfer->len = 4;
+
+       ret = spi_sync(ks->spidev, msg);
+       if (ret < 0)
+               ks_err(ks, "spi_sync() failed\n");
+}
+
+/**
+ * ks8851_rx_1msg - select whether to use one or two messages for spi read
+ * @ks: The device structure
+ *
+ * Return whether to generate a single message with a tx and rx buffer
+ * supplied to spi_sync(), or alternatively send the tx and rx buffers
+ * as separate messages.
+ *
+ * Depending on the hardware in use, a single message may be more efficient
+ * on interrupts or work done by the driver.
+ *
+ * This currently always returns true until we add some per-device data passed
+ * from the platform code to specify which mode is better.
+ */
+static inline bool ks8851_rx_1msg(struct ks8851_net *ks)
+{
+       return true;
+}
+
+/**
+ * ks8851_rdreg - issue read register command and return the data
+ * @ks: The device state
+ * @op: The register address and byte enables in message format.
+ * @rxb: The RX buffer to return the result into
+ * @rxl: The length of data expected.
+ *
+ * This is the low level read call that issues the necessary spi message(s)
+ * to read data from the register specified in @op.
+ */
+static void ks8851_rdreg(struct ks8851_net *ks, unsigned op,
+                        u8 *rxb, unsigned rxl)
+{
+       struct spi_transfer *xfer;
+       struct spi_message *msg;
+       __le16 *txb = (__le16 *)ks->txd;
+       u8 *trx = ks->rxd;
+       int ret;
+
+       txb[0] = cpu_to_le16(op | KS_SPIOP_RD);
+
+       if (ks8851_rx_1msg(ks)) {
+               msg = &ks->spi_msg1;
+               xfer = &ks->spi_xfer1;
+
+               xfer->tx_buf = txb;
+               xfer->rx_buf = trx;
+               xfer->len = rxl + 2;
+       } else {
+               msg = &ks->spi_msg2;
+               xfer = ks->spi_xfer2;
+
+               xfer->tx_buf = txb;
+               xfer->rx_buf = NULL;
+               xfer->len = 2;
+
+               xfer++;
+               xfer->tx_buf = NULL;
+               xfer->rx_buf = trx;
+               xfer->len = rxl;
+       }
+
+       ret = spi_sync(ks->spidev, msg);
+       if (ret < 0)
+               ks_err(ks, "read: spi_sync() failed\n");
+       else if (ks8851_rx_1msg(ks))
+               memcpy(rxb, trx + 2, rxl);
+       else
+               memcpy(rxb, trx, rxl);
+}
+
+/**
+ * ks8851_rdreg8 - read 8 bit register from device
+ * @ks: The chip information
+ * @reg: The register address
+ *
+ * Read a 8bit register from the chip, returning the result
+*/
+static unsigned ks8851_rdreg8(struct ks8851_net *ks, unsigned reg)
+{
+       u8 rxb[1];
+
+       ks8851_rdreg(ks, MK_OP(1 << (reg & 3), reg), rxb, 1);
+       return rxb[0];
+}
+
+/**
+ * ks8851_rdreg16 - read 16 bit register from device
+ * @ks: The chip information
+ * @reg: The register address
+ *
+ * Read a 16bit register from the chip, returning the result
+*/
+static unsigned ks8851_rdreg16(struct ks8851_net *ks, unsigned reg)
+{
+       __le16 rx = 0;
+
+       ks8851_rdreg(ks, MK_OP(reg & 2 ? 0xC : 0x3, reg), (u8 *)&rx, 2);
+       return le16_to_cpu(rx);
+}
+
+/**
+ * ks8851_rdreg32 - read 32 bit register from device
+ * @ks: The chip information
+ * @reg: The register address
+ *
+ * Read a 32bit register from the chip.
+ *
+ * Note, this read requires the address be aligned to 4 bytes.
+*/
+static unsigned ks8851_rdreg32(struct ks8851_net *ks, unsigned reg)
+{
+       __le32 rx = 0;
+
+       WARN_ON(reg & 3);
+
+       ks8851_rdreg(ks, MK_OP(0xf, reg), (u8 *)&rx, 4);
+       return le32_to_cpu(rx);
+}
+
+/**
+ * ks8851_soft_reset - issue one of the soft reset to the device
+ * @ks: The device state.
+ * @op: The bit(s) to set in the GRR
+ *
+ * Issue the relevant soft-reset command to the device's GRR register
+ * specified by @op.
+ *
+ * Note, the delays are in there as a caution to ensure that the reset
+ * has time to take effect and then complete. Since the datasheet does
+ * not currently specify the exact sequence, we have chosen something
+ * that seems to work with our device.
+ */
+static void ks8851_soft_reset(struct ks8851_net *ks, unsigned op)
+{
+       ks8851_wrreg16(ks, KS_GRR, op);
+       mdelay(1);      /* wait a short time to effect reset */
+       ks8851_wrreg16(ks, KS_GRR, 0);
+       mdelay(1);      /* wait for condition to clear */
+}
+
+/**
+ * ks8851_write_mac_addr - write mac address to device registers
+ * @dev: The network device
+ *
+ * Update the KS8851 MAC address registers from the address in @dev.
+ *
+ * This call assumes that the chip is not running, so there is no need to
+ * shutdown the RXQ process whilst setting this.
+*/
+static int ks8851_write_mac_addr(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       u16 *mcp = (u16 *)dev->dev_addr;
+
+       mutex_lock(&ks->lock);
+
+       ks8851_wrreg16(ks, KS_MARL, mcp[0]);
+       ks8851_wrreg16(ks, KS_MARM, mcp[1]);
+       ks8851_wrreg16(ks, KS_MARH, mcp[2]);
+
+       mutex_unlock(&ks->lock);
+
+       return 0;
+}
+
+/**
+ * ks8851_init_mac - initialise the mac address
+ * @ks: The device structure
+ *
+ * Get or create the initial mac address for the device and then set that
+ * into the station address register. Currently we assume that the device
+ * does not have a valid mac address in it, and so we use random_ether_addr()
+ * to create a new one.
+ *
+ * In future, the driver should check to see if the device has an EEPROM
+ * attached and whether that has a valid ethernet address in it.
+ */
+static void ks8851_init_mac(struct ks8851_net *ks)
+{
+       struct net_device *dev = ks->netdev;
+
+       random_ether_addr(dev->dev_addr);
+       ks8851_write_mac_addr(dev);
+}
+
+/**
+ * ks8851_irq - device interrupt handler
+ * @irq: Interrupt number passed from the IRQ hnalder.
+ * @pw: The private word passed to register_irq(), our struct ks8851_net.
+ *
+ * Disable the interrupt from happening again until we've processed the
+ * current status by scheduling ks8851_irq_work().
+ */
+static irqreturn_t ks8851_irq(int irq, void *pw)
+{
+       struct ks8851_net *ks = pw;
+
+       disable_irq_nosync(irq);
+       schedule_work(&ks->irq_work);
+       return IRQ_HANDLED;
+}
+
+/**
+ * ks8851_rdfifo - read data from the receive fifo
+ * @ks: The device state.
+ * @buff: The buffer address
+ * @len: The length of the data to read
+ *
+ * Issue an RXQ FIFO read command and read the @len ammount of data from
+ * the FIFO into the buffer specified by @buff.
+ */
+static void ks8851_rdfifo(struct ks8851_net *ks, u8 *buff, unsigned len)
+{
+       struct spi_transfer *xfer = ks->spi_xfer2;
+       struct spi_message *msg = &ks->spi_msg2;
+       u8 txb[1];
+       int ret;
+
+       if (netif_msg_rx_status(ks))
+               ks_dbg(ks, "%s: %d@%p\n", __func__, len, buff);
+
+       /* set the operation we're issuing */
+       txb[0] = KS_SPIOP_RXFIFO;
+
+       xfer->tx_buf = txb;
+       xfer->rx_buf = NULL;
+       xfer->len = 1;
+
+       xfer++;
+       xfer->rx_buf = buff;
+       xfer->tx_buf = NULL;
+       xfer->len = len;
+
+       ret = spi_sync(ks->spidev, msg);
+       if (ret < 0)
+               ks_err(ks, "%s: spi_sync() failed\n", __func__);
+}
+
+/**
+ * ks8851_dbg_dumpkkt - dump initial packet contents to debug
+ * @ks: The device state
+ * @rxpkt: The data for the received packet
+ *
+ * Dump the initial data from the packet to dev_dbg().
+*/
+static void ks8851_dbg_dumpkkt(struct ks8851_net *ks, u8 *rxpkt)
+{
+       ks_dbg(ks, "pkt %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
+              rxpkt[4], rxpkt[5], rxpkt[6], rxpkt[7],
+              rxpkt[8], rxpkt[9], rxpkt[10], rxpkt[11],
+              rxpkt[12], rxpkt[13], rxpkt[14], rxpkt[15]);
+}
+
+/**
+ * ks8851_rx_pkts - receive packets from the host
+ * @ks: The device information.
+ *
+ * This is called from the IRQ work queue when the system detects that there
+ * are packets in the receive queue. Find out how many packets there are and
+ * read them from the FIFO.
+ */
+static void ks8851_rx_pkts(struct ks8851_net *ks)
+{
+       struct sk_buff *skb;
+       unsigned rxfc;
+       unsigned rxlen;
+       unsigned rxstat;
+       u32 rxh;
+       u8 *rxpkt;
+
+       rxfc = ks8851_rdreg8(ks, KS_RXFC);
+
+       if (netif_msg_rx_status(ks))
+               ks_dbg(ks, "%s: %d packets\n", __func__, rxfc);
+
+       /* Currently we're issuing a read per packet, but we could possibly
+        * improve the code by issuing a single read, getting the receive
+        * header, allocating the packet and then reading the packet data
+        * out in one go.
+        *
+        * This form of operation would require us to hold the SPI bus'
+        * chipselect low during the entie transaction to avoid any
+        * reset to the data stream comming from the chip.
+        */
+
+       for (; rxfc != 0; rxfc--) {
+               rxh = ks8851_rdreg32(ks, KS_RXFHSR);
+               rxstat = rxh & 0xffff;
+               rxlen = rxh >> 16;
+
+               if (netif_msg_rx_status(ks))
+                       ks_dbg(ks, "rx: stat 0x%04x, len 0x%04x\n",
+                               rxstat, rxlen);
+
+               /* the length of the packet includes the 32bit CRC */
+
+               /* set dma read address */
+               ks8851_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI | 0x00);
+
+               /* start the packet dma process, and set auto-dequeue rx */
+               ks8851_wrreg16(ks, KS_RXQCR,
+                              ks->rc_rxqcr | RXQCR_SDA | RXQCR_ADRFE);
+
+               if (rxlen > 0) {
+                       skb = netdev_alloc_skb(ks->netdev, rxlen + 2 + 8);
+                       if (!skb) {
+                               /* todo - dump frame and move on */
+                       }
+
+                       /* two bytes to ensure ip is aligned, and four bytes
+                        * for the status header and 4 bytes of garbage */
+                       skb_reserve(skb, 2 + 4 + 4);
+
+                       rxpkt = skb_put(skb, rxlen - 4) - 8;
+
+                       /* align the packet length to 4 bytes, and add 4 bytes
+                        * as we're getting the rx status header as well */
+                       ks8851_rdfifo(ks, rxpkt, ALIGN(rxlen, 4) + 8);
+
+                       if (netif_msg_pktdata(ks))
+                               ks8851_dbg_dumpkkt(ks, rxpkt);
+
+                       skb->protocol = eth_type_trans(skb, ks->netdev);
+                       netif_rx(skb);
+
+                       ks->netdev->stats.rx_packets++;
+                       ks->netdev->stats.rx_bytes += rxlen - 4;
+               }
+
+               ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
+       }
+}
+
+/**
+ * ks8851_irq_work - work queue handler for dealing with interrupt requests
+ * @work: The work structure that was scheduled by schedule_work()
+ *
+ * This is the handler invoked when the ks8851_irq() is called to find out
+ * what happened, as we cannot allow ourselves to sleep whilst waiting for
+ * anything other process has the chip's lock.
+ *
+ * Read the interrupt status, work out what needs to be done and then clear
+ * any of the interrupts that are not needed.
+ */
+static void ks8851_irq_work(struct work_struct *work)
+{
+       struct ks8851_net *ks = container_of(work, struct ks8851_net, irq_work);
+       unsigned status;
+       unsigned handled = 0;
+
+       mutex_lock(&ks->lock);
+
+       status = ks8851_rdreg16(ks, KS_ISR);
+
+       if (netif_msg_intr(ks))
+               dev_dbg(&ks->spidev->dev, "%s: status 0x%04x\n",
+                       __func__, status);
+
+       if (status & IRQ_LCI) {
+               /* should do something about checking link status */
+               handled |= IRQ_LCI;
+       }
+
+       if (status & IRQ_LDI) {
+               u16 pmecr = ks8851_rdreg16(ks, KS_PMECR);
+               pmecr &= ~PMECR_WKEVT_MASK;
+               ks8851_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
+
+               handled |= IRQ_LDI;
+       }
+
+       if (status & IRQ_RXPSI)
+               handled |= IRQ_RXPSI;
+
+       if (status & IRQ_TXI) {
+               handled |= IRQ_TXI;
+
+               /* no lock here, tx queue should have been stopped */
+
+               /* update our idea of how much tx space is available to the
+                * system */
+               ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
+
+               if (netif_msg_intr(ks))
+                       ks_dbg(ks, "%s: txspace %d\n", __func__, ks->tx_space);
+       }
+
+       if (status & IRQ_RXI)
+               handled |= IRQ_RXI;
+
+       if (status & IRQ_SPIBEI) {
+               dev_err(&ks->spidev->dev, "%s: spi bus error\n", __func__);
+               handled |= IRQ_SPIBEI;
+       }
+
+       ks8851_wrreg16(ks, KS_ISR, handled);
+
+       if (status & IRQ_RXI) {
+               /* the datasheet says to disable the rx interrupt during
+                * packet read-out, however we're masking the interrupt
+                * from the device so do not bother masking just the RX
+                * from the device. */
+
+               ks8851_rx_pkts(ks);
+       }
+
+       /* if something stopped the rx process, probably due to wanting
+        * to change the rx settings, then do something about restarting
+        * it. */
+       if (status & IRQ_RXPSI) {
+               struct ks8851_rxctrl *rxc = &ks->rxctrl;
+
+               /* update the multicast hash table */
+               ks8851_wrreg16(ks, KS_MAHTR0, rxc->mchash[0]);
+               ks8851_wrreg16(ks, KS_MAHTR1, rxc->mchash[1]);
+               ks8851_wrreg16(ks, KS_MAHTR2, rxc->mchash[2]);
+               ks8851_wrreg16(ks, KS_MAHTR3, rxc->mchash[3]);
+
+               ks8851_wrreg16(ks, KS_RXCR2, rxc->rxcr2);
+               ks8851_wrreg16(ks, KS_RXCR1, rxc->rxcr1);
+       }
+
+       mutex_unlock(&ks->lock);
+
+       if (status & IRQ_TXI)
+               netif_wake_queue(ks->netdev);
+
+       enable_irq(ks->netdev->irq);
+}
+
+/**
+ * calc_txlen - calculate size of message to send packet
+ * @len: Lenght of data
+ *
+ * Returns the size of the TXFIFO message needed to send
+ * this packet.
+ */
+static inline unsigned calc_txlen(unsigned len)
+{
+       return ALIGN(len + 4, 4);
+}
+
+/**
+ * ks8851_wrpkt - write packet to TX FIFO
+ * @ks: The device state.
+ * @txp: The sk_buff to transmit.
+ * @irq: IRQ on completion of the packet.
+ *
+ * Send the @txp to the chip. This means creating the relevant packet header
+ * specifying the length of the packet and the other information the chip
+ * needs, such as IRQ on completion. Send the header and the packet data to
+ * the device.
+ */
+static void ks8851_wrpkt(struct ks8851_net *ks, struct sk_buff *txp, bool irq)
+{
+       struct spi_transfer *xfer = ks->spi_xfer2;
+       struct spi_message *msg = &ks->spi_msg2;
+       unsigned fid = 0;
+       int ret;
+
+       if (netif_msg_tx_queued(ks))
+               dev_dbg(&ks->spidev->dev, "%s: skb %p, %d@%p, irq %d\n",
+                       __func__, txp, txp->len, txp->data, irq);
+
+       fid = ks->fid++;
+       fid &= TXFR_TXFID_MASK;
+
+       if (irq)
+               fid |= TXFR_TXIC;       /* irq on completion */
+
+       /* start header at txb[1] to align txw entries */
+       ks->txh.txb[1] = KS_SPIOP_TXFIFO;
+       ks->txh.txw[1] = cpu_to_le16(fid);
+       ks->txh.txw[2] = cpu_to_le16(txp->len);
+
+       xfer->tx_buf = &ks->txh.txb[1];
+       xfer->rx_buf = NULL;
+       xfer->len = 5;
+
+       xfer++;
+       xfer->tx_buf = txp->data;
+       xfer->rx_buf = NULL;
+       xfer->len = ALIGN(txp->len, 4);
+
+       ret = spi_sync(ks->spidev, msg);
+       if (ret < 0)
+               ks_err(ks, "%s: spi_sync() failed\n", __func__);
+}
+
+/**
+ * ks8851_done_tx - update and then free skbuff after transmitting
+ * @ks: The device state
+ * @txb: The buffer transmitted
+ */
+static void ks8851_done_tx(struct ks8851_net *ks, struct sk_buff *txb)
+{
+       struct net_device *dev = ks->netdev;
+
+       dev->stats.tx_bytes += txb->len;
+       dev->stats.tx_packets++;
+
+       dev_kfree_skb(txb);
+}
+
+/**
+ * ks8851_tx_work - process tx packet(s)
+ * @work: The work strucutre what was scheduled.
+ *
+ * This is called when a number of packets have been scheduled for
+ * transmission and need to be sent to the device.
+ */
+static void ks8851_tx_work(struct work_struct *work)
+{
+       struct ks8851_net *ks = container_of(work, struct ks8851_net, tx_work);
+       struct sk_buff *txb;
+       bool last = false;
+
+       mutex_lock(&ks->lock);
+
+       while (!last) {
+               txb = skb_dequeue(&ks->txq);
+               last = skb_queue_empty(&ks->txq);
+
+               ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
+               ks8851_wrpkt(ks, txb, last);
+               ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
+               ks8851_wrreg16(ks, KS_TXQCR, TXQCR_METFE);
+
+               ks8851_done_tx(ks, txb);
+       }
+
+       mutex_unlock(&ks->lock);
+}
+
+/**
+ * ks8851_set_powermode - set power mode of the device
+ * @ks: The device state
+ * @pwrmode: The power mode value to write to KS_PMECR.
+ *
+ * Change the power mode of the chip.
+ */
+static void ks8851_set_powermode(struct ks8851_net *ks, unsigned pwrmode)
+{
+       unsigned pmecr;
+
+       if (netif_msg_hw(ks))
+               ks_dbg(ks, "setting power mode %d\n", pwrmode);
+
+       pmecr = ks8851_rdreg16(ks, KS_PMECR);
+       pmecr &= ~PMECR_PM_MASK;
+       pmecr |= pwrmode;
+
+       ks8851_wrreg16(ks, KS_PMECR, pmecr);
+}
+
+/**
+ * ks8851_net_open - open network device
+ * @dev: The network device being opened.
+ *
+ * Called when the network device is marked active, such as a user executing
+ * 'ifconfig up' on the device.
+ */
+static int ks8851_net_open(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+
+       /* lock the card, even if we may not actually be doing anything
+        * else at the moment */
+       mutex_lock(&ks->lock);
+
+       if (netif_msg_ifup(ks))
+               ks_dbg(ks, "opening %s\n", dev->name);
+
+       /* bring chip out of any power saving mode it was in */
+       ks8851_set_powermode(ks, PMECR_PM_NORMAL);
+
+       /* issue a soft reset to the RX/TX QMU to put it into a known
+        * state. */
+       ks8851_soft_reset(ks, GRR_QMU);
+
+       /* setup transmission parameters */
+
+       ks8851_wrreg16(ks, KS_TXCR, (TXCR_TXE | /* enable transmit process */
+                                    TXCR_TXPE | /* pad to min length */
+                                    TXCR_TXCRC | /* add CRC */
+                                    TXCR_TXFCE)); /* enable flow control */
+
+       /* auto-increment tx data, reset tx pointer */
+       ks8851_wrreg16(ks, KS_TXFDPR, TXFDPR_TXFPAI);
+
+       /* setup receiver control */
+
+       ks8851_wrreg16(ks, KS_RXCR1, (RXCR1_RXPAFMA | /*  from mac filter */
+                                     RXCR1_RXFCE | /* enable flow control */
+                                     RXCR1_RXBE | /* broadcast enable */
+                                     RXCR1_RXUE | /* unicast enable */
+                                     RXCR1_RXE)); /* enable rx block */
+
+       /* transfer entire frames out in one go */
+       ks8851_wrreg16(ks, KS_RXCR2, RXCR2_SRDBL_FRAME);
+
+       /* set receive counter timeouts */
+       ks8851_wrreg16(ks, KS_RXDTTR, 1000); /* 1ms after first frame to IRQ */
+       ks8851_wrreg16(ks, KS_RXDBCTR, 4096); /* >4Kbytes in buffer to IRQ */
+       ks8851_wrreg16(ks, KS_RXFCTR, 10);  /* 10 frames to IRQ */
+
+       ks->rc_rxqcr = (RXQCR_RXFCTE |  /* IRQ on frame count exceeded */
+                       RXQCR_RXDBCTE | /* IRQ on byte count exceeded */
+                       RXQCR_RXDTTE);  /* IRQ on time exceeded */
+
+       ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
+
+       /* clear then enable interrupts */
+
+#define STD_IRQ (IRQ_LCI |     /* Link Change */       \
+                IRQ_TXI |      /* TX done */           \
+                IRQ_RXI |      /* RX done */           \
+                IRQ_SPIBEI |   /* SPI bus error */     \
+                IRQ_TXPSI |    /* TX process stop */   \
+                IRQ_RXPSI)     /* RX process stop */
+
+       ks->rc_ier = STD_IRQ;
+       ks8851_wrreg16(ks, KS_ISR, STD_IRQ);
+       ks8851_wrreg16(ks, KS_IER, STD_IRQ);
+
+       netif_start_queue(ks->netdev);
+
+       if (netif_msg_ifup(ks))
+               ks_dbg(ks, "network device %s up\n", dev->name);
+
+       mutex_unlock(&ks->lock);
+       return 0;
+}
+
+/**
+ * ks8851_net_stop - close network device
+ * @dev: The device being closed.
+ *
+ * Called to close down a network device which has been active. Cancell any
+ * work, shutdown the RX and TX process and then place the chip into a low
+ * power state whilst it is not being used.
+ */
+static int ks8851_net_stop(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+
+       if (netif_msg_ifdown(ks))
+               ks_info(ks, "%s: shutting down\n", dev->name);
+
+       netif_stop_queue(dev);
+
+       mutex_lock(&ks->lock);
+
+       /* stop any outstanding work */
+       flush_work(&ks->irq_work);
+       flush_work(&ks->tx_work);
+       flush_work(&ks->rxctrl_work);
+
+       /* turn off the IRQs and ack any outstanding */
+       ks8851_wrreg16(ks, KS_IER, 0x0000);
+       ks8851_wrreg16(ks, KS_ISR, 0xffff);
+
+       /* shutdown RX process */
+       ks8851_wrreg16(ks, KS_RXCR1, 0x0000);
+
+       /* shutdown TX process */
+       ks8851_wrreg16(ks, KS_TXCR, 0x0000);
+
+       /* set powermode to soft power down to save power */
+       ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
+
+       /* ensure any queued tx buffers are dumped */
+       while (!skb_queue_empty(&ks->txq)) {
+               struct sk_buff *txb = skb_dequeue(&ks->txq);
+
+               if (netif_msg_ifdown(ks))
+                       ks_dbg(ks, "%s: freeing txb %p\n", __func__, txb);
+
+               dev_kfree_skb(txb);
+       }
+
+       mutex_unlock(&ks->lock);
+       return 0;
+}
+
+/**
+ * ks8851_start_xmit - transmit packet
+ * @skb: The buffer to transmit
+ * @dev: The device used to transmit the packet.
+ *
+ * Called by the network layer to transmit the @skb. Queue the packet for
+ * the device and schedule the necessary work to transmit the packet when
+ * it is free.
+ *
+ * We do this to firstly avoid sleeping with the network device locked,
+ * and secondly so we can round up more than one packet to transmit which
+ * means we can try and avoid generating too many transmit done interrupts.
+ */
+static int ks8851_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       unsigned needed = calc_txlen(skb->len);
+       int ret = NETDEV_TX_OK;
+
+       if (netif_msg_tx_queued(ks))
+               ks_dbg(ks, "%s: skb %p, %d@%p\n", __func__,
+                      skb, skb->len, skb->data);
+
+       spin_lock(&ks->statelock);
+
+       if (needed > ks->tx_space) {
+               netif_stop_queue(dev);
+               ret = NETDEV_TX_BUSY;
+       } else {
+               ks->tx_space -= needed;
+               skb_queue_tail(&ks->txq, skb);
+       }
+
+       spin_unlock(&ks->statelock);
+       schedule_work(&ks->tx_work);
+
+       return ret;
+}
+
+/**
+ * ks8851_rxctrl_work - work handler to change rx mode
+ * @work: The work structure this belongs to.
+ *
+ * Lock the device and issue the necessary changes to the receive mode from
+ * the network device layer. This is done so that we can do this without
+ * having to sleep whilst holding the network device lock.
+ *
+ * Since the recommendation from Micrel is that the RXQ is shutdown whilst the
+ * receive parameters are programmed, we issue a write to disable the RXQ and
+ * then wait for the interrupt handler to be triggered once the RXQ shutdown is
+ * complete. The interrupt handler then writes the new values into the chip.
+ */
+static void ks8851_rxctrl_work(struct work_struct *work)
+{
+       struct ks8851_net *ks = container_of(work, struct ks8851_net, rxctrl_work);
+
+       mutex_lock(&ks->lock);
+
+       /* need to shutdown RXQ before modifying filter parameters */
+       ks8851_wrreg16(ks, KS_RXCR1, 0x00);
+
+       mutex_unlock(&ks->lock);
+}
+
+static void ks8851_set_rx_mode(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       struct ks8851_rxctrl rxctrl;
+
+       memset(&rxctrl, 0, sizeof(rxctrl));
+
+       if (dev->flags & IFF_PROMISC) {
+               /* interface to receive everything */
+
+               rxctrl.rxcr1 = RXCR1_RXAE | RXCR1_RXINVF;
+       } else if (dev->flags & IFF_ALLMULTI) {
+               /* accept all multicast packets */
+
+               rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE |
+                               RXCR1_RXPAFMA | RXCR1_RXMAFMA);
+       } else if (dev->flags & IFF_MULTICAST && dev->mc_count > 0) {
+               struct dev_mc_list *mcptr = dev->mc_list;
+               u32 crc;
+               int i;
+
+               /* accept some multicast */
+
+               for (i = dev->mc_count; i > 0; i--) {
+                       crc = ether_crc(ETH_ALEN, mcptr->dmi_addr);
+                       crc >>= (32 - 6);  /* get top six bits */
+
+                       rxctrl.mchash[crc >> 4] |= (1 << (crc & 0xf));
+                       mcptr = mcptr->next;
+               }
+
+               rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXAE | RXCR1_RXPAFMA;
+       } else {
+               /* just accept broadcast / unicast */
+               rxctrl.rxcr1 = RXCR1_RXPAFMA;
+       }
+
+       rxctrl.rxcr1 |= (RXCR1_RXUE | /* unicast enable */
+                        RXCR1_RXBE | /* broadcast enable */
+                        RXCR1_RXE | /* RX process enable */
+                        RXCR1_RXFCE); /* enable flow control */
+
+       rxctrl.rxcr2 |= RXCR2_SRDBL_FRAME;
+
+       /* schedule work to do the actual set of the data if needed */
+
+       spin_lock(&ks->statelock);
+
+       if (memcmp(&rxctrl, &ks->rxctrl, sizeof(rxctrl)) != 0) {
+               memcpy(&ks->rxctrl, &rxctrl, sizeof(ks->rxctrl));
+               schedule_work(&ks->rxctrl_work);
+       }
+
+       spin_unlock(&ks->statelock);
+}
+
+static int ks8851_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr *sa = addr;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       if (!is_valid_ether_addr(sa->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
+       return ks8851_write_mac_addr(dev);
+}
+
+static int ks8851_net_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       return generic_mii_ioctl(&ks->mii, if_mii(req), cmd, NULL);
+}
+
+static const struct net_device_ops ks8851_netdev_ops = {
+       .ndo_open               = ks8851_net_open,
+       .ndo_stop               = ks8851_net_stop,
+       .ndo_do_ioctl           = ks8851_net_ioctl,
+       .ndo_start_xmit         = ks8851_start_xmit,
+       .ndo_set_mac_address    = ks8851_set_mac_address,
+       .ndo_set_rx_mode        = ks8851_set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/* ethtool support */
+
+static void ks8851_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *di)
+{
+       strlcpy(di->driver, "KS8851", sizeof(di->driver));
+       strlcpy(di->version, "1.00", sizeof(di->version));
+       strlcpy(di->bus_info, dev_name(dev->dev.parent), sizeof(di->bus_info));
+}
+
+static u32 ks8851_get_msglevel(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return ks->msg_enable;
+}
+
+static void ks8851_set_msglevel(struct net_device *dev, u32 to)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       ks->msg_enable = to;
+}
+
+static int ks8851_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return mii_ethtool_gset(&ks->mii, cmd);
+}
+
+static int ks8851_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return mii_ethtool_sset(&ks->mii, cmd);
+}
+
+static u32 ks8851_get_link(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return mii_link_ok(&ks->mii);
+}
+
+static int ks8851_nway_reset(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return mii_nway_restart(&ks->mii);
+}
+
+static const struct ethtool_ops ks8851_ethtool_ops = {
+       .get_drvinfo    = ks8851_get_drvinfo,
+       .get_msglevel   = ks8851_get_msglevel,
+       .set_msglevel   = ks8851_set_msglevel,
+       .get_settings   = ks8851_get_settings,
+       .set_settings   = ks8851_set_settings,
+       .get_link       = ks8851_get_link,
+       .nway_reset     = ks8851_nway_reset,
+};
+
+/* MII interface controls */
+
+/**
+ * ks8851_phy_reg - convert MII register into a KS8851 register
+ * @reg: MII register number.
+ *
+ * Return the KS8851 register number for the corresponding MII PHY register
+ * if possible. Return zero if the MII register has no direct mapping to the
+ * KS8851 register set.
+ */
+static int ks8851_phy_reg(int reg)
+{
+       switch (reg) {
+       case MII_BMCR:
+               return KS_P1MBCR;
+       case MII_BMSR:
+               return KS_P1MBSR;
+       case MII_PHYSID1:
+               return KS_PHY1ILR;
+       case MII_PHYSID2:
+               return KS_PHY1IHR;
+       case MII_ADVERTISE:
+               return KS_P1ANAR;
+       case MII_LPA:
+               return KS_P1ANLPR;
+       }
+
+       return 0x0;
+}
+
+/**
+ * ks8851_phy_read - MII interface PHY register read.
+ * @dev: The network device the PHY is on.
+ * @phy_addr: Address of PHY (ignored as we only have one)
+ * @reg: The register to read.
+ *
+ * This call reads data from the PHY register specified in @reg. Since the
+ * device does not support all the MII registers, the non-existant values
+ * are always returned as zero.
+ *
+ * We return zero for unsupported registers as the MII code does not check
+ * the value returned for any error status, and simply returns it to the
+ * caller. The mii-tool that the driver was tested with takes any -ve error
+ * as real PHY capabilities, thus displaying incorrect data to the user.
+ */
+static int ks8851_phy_read(struct net_device *dev, int phy_addr, int reg)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       int ksreg;
+       int result;
+
+       ksreg = ks8851_phy_reg(reg);
+       if (!ksreg)
+               return 0x0;     /* no error return allowed, so use zero */
+
+       mutex_lock(&ks->lock);
+       result = ks8851_rdreg16(ks, ksreg);
+       mutex_unlock(&ks->lock);
+
+       return result;
+}
+
+static void ks8851_phy_write(struct net_device *dev,
+                            int phy, int reg, int value)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       int ksreg;
+
+       ksreg = ks8851_phy_reg(reg);
+       if (ksreg) {
+               mutex_lock(&ks->lock);
+               ks8851_wrreg16(ks, ksreg, value);
+               mutex_unlock(&ks->lock);
+       }
+}
+
+/**
+ * ks8851_read_selftest - read the selftest memory info.
+ * @ks: The device state
+ *
+ * Read and check the TX/RX memory selftest information.
+ */
+static int ks8851_read_selftest(struct ks8851_net *ks)
+{
+       unsigned both_done = MBIR_TXMBF | MBIR_RXMBF;
+       int ret = 0;
+       unsigned rd;
+
+       rd = ks8851_rdreg16(ks, KS_MBIR);
+
+       if ((rd & both_done) != both_done) {
+               ks_warn(ks, "Memory selftest not finished\n");
+               return 0;
+       }
+
+       if (rd & MBIR_TXMBFA) {
+               ks_err(ks, "TX memory selftest fail\n");
+               ret |= 1;
+       }
+
+       if (rd & MBIR_RXMBFA) {
+               ks_err(ks, "RX memory selftest fail\n");
+               ret |= 2;
+       }
+
+       return 0;
+}
+
+/* driver bus management functions */
+
+static int __devinit ks8851_probe(struct spi_device *spi)
+{
+       struct net_device *ndev;
+       struct ks8851_net *ks;
+       int ret;
+
+       ndev = alloc_etherdev(sizeof(struct ks8851_net));
+       if (!ndev) {
+               dev_err(&spi->dev, "failed to alloc ethernet device\n");
+               return -ENOMEM;
+       }
+
+       spi->bits_per_word = 8;
+
+       ks = netdev_priv(ndev);
+
+       ks->netdev = ndev;
+       ks->spidev = spi;
+       ks->tx_space = 6144;
+
+       mutex_init(&ks->lock);
+       spin_lock_init(&ks->statelock);
+
+       INIT_WORK(&ks->tx_work, ks8851_tx_work);
+       INIT_WORK(&ks->irq_work, ks8851_irq_work);
+       INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work);
+
+       /* initialise pre-made spi transfer messages */
+
+       spi_message_init(&ks->spi_msg1);
+       spi_message_add_tail(&ks->spi_xfer1, &ks->spi_msg1);
+
+       spi_message_init(&ks->spi_msg2);
+       spi_message_add_tail(&ks->spi_xfer2[0], &ks->spi_msg2);
+       spi_message_add_tail(&ks->spi_xfer2[1], &ks->spi_msg2);
+
+       /* setup mii state */
+       ks->mii.dev             = ndev;
+       ks->mii.phy_id          = 1,
+       ks->mii.phy_id_mask     = 1;
+       ks->mii.reg_num_mask    = 0xf;
+       ks->mii.mdio_read       = ks8851_phy_read;
+       ks->mii.mdio_write      = ks8851_phy_write;
+
+       dev_info(&spi->dev, "message enable is %d\n", msg_enable);
+
+       /* set the default message enable */
+       ks->msg_enable = netif_msg_init(msg_enable, (NETIF_MSG_DRV |
+                                                    NETIF_MSG_PROBE |
+                                                    NETIF_MSG_LINK));
+
+       skb_queue_head_init(&ks->txq);
+
+       SET_ETHTOOL_OPS(ndev, &ks8851_ethtool_ops);
+       SET_NETDEV_DEV(ndev, &spi->dev);
+
+       dev_set_drvdata(&spi->dev, ks);
+
+       ndev->if_port = IF_PORT_100BASET;
+       ndev->netdev_ops = &ks8851_netdev_ops;
+       ndev->irq = spi->irq;
+
+       /* simple check for a valid chip being connected to the bus */
+
+       if ((ks8851_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) {
+               dev_err(&spi->dev, "failed to read device ID\n");
+               ret = -ENODEV;
+               goto err_id;
+       }
+
+       ks8851_read_selftest(ks);
+       ks8851_init_mac(ks);
+
+       ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
+                         ndev->name, ks);
+       if (ret < 0) {
+               dev_err(&spi->dev, "failed to get irq\n");
+               goto err_irq;
+       }
+
+       ret = register_netdev(ndev);
+       if (ret) {
+               dev_err(&spi->dev, "failed to register network device\n");
+               goto err_netdev;
+       }
+
+       dev_info(&spi->dev, "revision %d, MAC %pM, IRQ %d\n",
+                CIDER_REV_GET(ks8851_rdreg16(ks, KS_CIDER)),
+                ndev->dev_addr, ndev->irq);
+
+       return 0;
+
+
+err_netdev:
+       free_irq(ndev->irq, ndev);
+
+err_id:
+err_irq:
+       free_netdev(ndev);
+       return ret;
+}
+
+static int __devexit ks8851_remove(struct spi_device *spi)
+{
+       struct ks8851_net *priv = dev_get_drvdata(&spi->dev);
+
+       if (netif_msg_drv(priv))
+               dev_info(&spi->dev, "remove");
+
+       unregister_netdev(priv->netdev);
+       free_irq(spi->irq, priv);
+       free_netdev(priv->netdev);
+
+       return 0;
+}
+
+static struct spi_driver ks8851_driver = {
+       .driver = {
+               .name = "ks8851",
+               .owner = THIS_MODULE,
+       },
+       .probe = ks8851_probe,
+       .remove = __devexit_p(ks8851_remove),
+};
+
+static int __init ks8851_init(void)
+{
+       return spi_register_driver(&ks8851_driver);
+}
+
+static void __exit ks8851_exit(void)
+{
+       spi_unregister_driver(&ks8851_driver);
+}
+
+module_init(ks8851_init);
+module_exit(ks8851_exit);
+
+MODULE_DESCRIPTION("KS8851 Network driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+
+module_param_named(message, msg_enable, int, 0);
+MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)");
diff --git a/drivers/net/ks8851.h b/drivers/net/ks8851.h
new file mode 100644 (file)
index 0000000..85abe14
--- /dev/null
@@ -0,0 +1,296 @@
+/* drivers/net/ks8851.h
+ *
+ * Copyright 2009 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * KS8851 register definitions
+ *
+ * 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 KS_CCR                                 0x08
+#define CCR_EEPROM                             (1 << 9)
+#define CCR_SPI                                        (1 << 8)
+#define CCR_32PIN                              (1 << 0)
+
+/* MAC address registers */
+#define KS_MARL                                        0x10
+#define KS_MARM                                        0x12
+#define KS_MARH                                        0x14
+
+#define KS_OBCR                                        0x20
+#define OBCR_ODS_16mA                          (1 << 6)
+
+#define KS_EEPCR                               0x22
+#define EEPCR_EESA                             (1 << 4)
+#define EEPCR_EESB                             (1 << 3)
+#define EEPCR_EEDO                             (1 << 2)
+#define EEPCR_EESCK                            (1 << 1)
+#define EEPCR_EECS                             (1 << 0)
+
+#define KS_MBIR                                        0x24
+#define MBIR_TXMBF                             (1 << 12)
+#define MBIR_TXMBFA                            (1 << 11)
+#define MBIR_RXMBF                             (1 << 4)
+#define MBIR_RXMBFA                            (1 << 3)
+
+#define KS_GRR                                 0x26
+#define GRR_QMU                                        (1 << 1)
+#define GRR_GSR                                        (1 << 0)
+
+#define KS_WFCR                                        0x2A
+#define WFCR_MPRXE                             (1 << 7)
+#define WFCR_WF3E                              (1 << 3)
+#define WFCR_WF2E                              (1 << 2)
+#define WFCR_WF1E                              (1 << 1)
+#define WFCR_WF0E                              (1 << 0)
+
+#define KS_WF0CRC0                             0x30
+#define KS_WF0CRC1                             0x32
+#define KS_WF0BM0                              0x34
+#define KS_WF0BM1                              0x36
+#define KS_WF0BM2                              0x38
+#define KS_WF0BM3                              0x3A
+
+#define KS_WF1CRC0                             0x40
+#define KS_WF1CRC1                             0x42
+#define KS_WF1BM0                              0x44
+#define KS_WF1BM1                              0x46
+#define KS_WF1BM2                              0x48
+#define KS_WF1BM3                              0x4A
+
+#define KS_WF2CRC0                             0x50
+#define KS_WF2CRC1                             0x52
+#define KS_WF2BM0                              0x54
+#define KS_WF2BM1                              0x56
+#define KS_WF2BM2                              0x58
+#define KS_WF2BM3                              0x5A
+
+#define KS_WF3CRC0                             0x60
+#define KS_WF3CRC1                             0x62
+#define KS_WF3BM0                              0x64
+#define KS_WF3BM1                              0x66
+#define KS_WF3BM2                              0x68
+#define KS_WF3BM3                              0x6A
+
+#define KS_TXCR                                        0x70
+#define TXCR_TCGICMP                           (1 << 8)
+#define TXCR_TCGUDP                            (1 << 7)
+#define TXCR_TCGTCP                            (1 << 6)
+#define TXCR_TCGIP                             (1 << 5)
+#define TXCR_FTXQ                              (1 << 4)
+#define TXCR_TXFCE                             (1 << 3)
+#define TXCR_TXPE                              (1 << 2)
+#define TXCR_TXCRC                             (1 << 1)
+#define TXCR_TXE                               (1 << 0)
+
+#define KS_TXSR                                        0x72
+#define TXSR_TXLC                              (1 << 13)
+#define TXSR_TXMC                              (1 << 12)
+#define TXSR_TXFID_MASK                                (0x3f << 0)
+#define TXSR_TXFID_SHIFT                       (0)
+#define TXSR_TXFID_GET(_v)                     (((_v) >> 0) & 0x3f)
+
+#define KS_RXCR1                               0x74
+#define RXCR1_FRXQ                             (1 << 15)
+#define RXCR1_RXUDPFCC                         (1 << 14)
+#define RXCR1_RXTCPFCC                         (1 << 13)
+#define RXCR1_RXIPFCC                          (1 << 12)
+#define RXCR1_RXPAFMA                          (1 << 11)
+#define RXCR1_RXFCE                            (1 << 10)
+#define RXCR1_RXEFE                            (1 << 9)
+#define RXCR1_RXMAFMA                          (1 << 8)
+#define RXCR1_RXBE                             (1 << 7)
+#define RXCR1_RXME                             (1 << 6)
+#define RXCR1_RXUE                             (1 << 5)
+#define RXCR1_RXAE                             (1 << 4)
+#define RXCR1_RXINVF                           (1 << 1)
+#define RXCR1_RXE                              (1 << 0)
+
+#define KS_RXCR2                               0x76
+#define RXCR2_SRDBL_MASK                       (0x7 << 5)
+#define RXCR2_SRDBL_SHIFT                      (5)
+#define RXCR2_SRDBL_4B                         (0x0 << 5)
+#define RXCR2_SRDBL_8B                         (0x1 << 5)
+#define RXCR2_SRDBL_16B                                (0x2 << 5)
+#define RXCR2_SRDBL_32B                                (0x3 << 5)
+#define RXCR2_SRDBL_FRAME                      (0x4 << 5)
+#define RXCR2_IUFFP                            (1 << 4)
+#define RXCR2_RXIUFCEZ                         (1 << 3)
+#define RXCR2_UDPLFE                           (1 << 2)
+#define RXCR2_RXICMPFCC                                (1 << 1)
+#define RXCR2_RXSAF                            (1 << 0)
+
+#define KS_TXMIR                               0x78
+
+#define KS_RXFHSR                              0x7C
+#define RXFSHR_RXFV                            (1 << 15)
+#define RXFSHR_RXICMPFCS                       (1 << 13)
+#define RXFSHR_RXIPFCS                         (1 << 12)
+#define RXFSHR_RXTCPFCS                                (1 << 11)
+#define RXFSHR_RXUDPFCS                                (1 << 10)
+#define RXFSHR_RXBF                            (1 << 7)
+#define RXFSHR_RXMF                            (1 << 6)
+#define RXFSHR_RXUF                            (1 << 5)
+#define RXFSHR_RXMR                            (1 << 4)
+#define RXFSHR_RXFT                            (1 << 3)
+#define RXFSHR_RXFTL                           (1 << 2)
+#define RXFSHR_RXRF                            (1 << 1)
+#define RXFSHR_RXCE                            (1 << 0)
+
+#define KS_RXFHBCR                             0x7E
+#define KS_TXQCR                               0x80
+#define TXQCR_AETFE                            (1 << 2)
+#define TXQCR_TXQMAM                           (1 << 1)
+#define TXQCR_METFE                            (1 << 0)
+
+#define KS_RXQCR                               0x82
+#define RXQCR_RXDTTS                           (1 << 12)
+#define RXQCR_RXDBCTS                          (1 << 11)
+#define RXQCR_RXFCTS                           (1 << 10)
+#define RXQCR_RXIPHTOE                         (1 << 9)
+#define RXQCR_RXDTTE                           (1 << 7)
+#define RXQCR_RXDBCTE                          (1 << 6)
+#define RXQCR_RXFCTE                           (1 << 5)
+#define RXQCR_ADRFE                            (1 << 4)
+#define RXQCR_SDA                              (1 << 3)
+#define RXQCR_RRXEF                            (1 << 0)
+
+#define KS_TXFDPR                              0x84
+#define TXFDPR_TXFPAI                          (1 << 14)
+#define TXFDPR_TXFP_MASK                       (0x7ff << 0)
+#define TXFDPR_TXFP_SHIFT                      (0)
+
+#define KS_RXFDPR                              0x86
+#define RXFDPR_RXFPAI                          (1 << 14)
+
+#define KS_RXDTTR                              0x8C
+#define KS_RXDBCTR                             0x8E
+
+#define KS_IER                                 0x90
+#define KS_ISR                                 0x92
+#define IRQ_LCI                                        (1 << 15)
+#define IRQ_TXI                                        (1 << 14)
+#define IRQ_RXI                                        (1 << 13)
+#define IRQ_RXOI                               (1 << 11)
+#define IRQ_TXPSI                              (1 << 9)
+#define IRQ_RXPSI                              (1 << 8)
+#define IRQ_TXSAI                              (1 << 6)
+#define IRQ_RXWFDI                             (1 << 5)
+#define IRQ_RXMPDI                             (1 << 4)
+#define IRQ_LDI                                        (1 << 3)
+#define IRQ_EDI                                        (1 << 2)
+#define IRQ_SPIBEI                             (1 << 1)
+#define IRQ_DEDI                               (1 << 0)
+
+#define KS_RXFCTR                              0x9C
+#define KS_RXFC                                        0x9D
+#define RXFCTR_RXFC_MASK                       (0xff << 8)
+#define RXFCTR_RXFC_SHIFT                      (8)
+#define RXFCTR_RXFC_GET(_v)                    (((_v) >> 8) & 0xff)
+#define RXFCTR_RXFCT_MASK                      (0xff << 0)
+#define RXFCTR_RXFCT_SHIFT                     (0)
+
+#define KS_TXNTFSR                             0x9E
+
+#define KS_MAHTR0                              0xA0
+#define KS_MAHTR1                              0xA2
+#define KS_MAHTR2                              0xA4
+#define KS_MAHTR3                              0xA6
+
+#define KS_FCLWR                               0xB0
+#define KS_FCHWR                               0xB2
+#define KS_FCOWR                               0xB4
+
+#define KS_CIDER                               0xC0
+#define CIDER_ID                               0x8870
+#define CIDER_REV_MASK                         (0x7 << 1)
+#define CIDER_REV_SHIFT                                (1)
+#define CIDER_REV_GET(_v)                      (((_v) >> 1) & 0x7)
+
+#define KS_CGCR                                        0xC6
+
+#define KS_IACR                                        0xC8
+#define IACR_RDEN                              (1 << 12)
+#define IACR_TSEL_MASK                         (0x3 << 10)
+#define IACR_TSEL_SHIFT                                (10)
+#define IACR_TSEL_MIB                          (0x3 << 10)
+#define IACR_ADDR_MASK                         (0x1f << 0)
+#define IACR_ADDR_SHIFT                                (0)
+
+#define KS_IADLR                               0xD0
+#define KS_IAHDR                               0xD2
+
+#define KS_PMECR                               0xD4
+#define PMECR_PME_DELAY                                (1 << 14)
+#define PMECR_PME_POL                          (1 << 12)
+#define PMECR_WOL_WAKEUP                       (1 << 11)
+#define PMECR_WOL_MAGICPKT                     (1 << 10)
+#define PMECR_WOL_LINKUP                       (1 << 9)
+#define PMECR_WOL_ENERGY                       (1 << 8)
+#define PMECR_AUTO_WAKE_EN                     (1 << 7)
+#define PMECR_WAKEUP_NORMAL                    (1 << 6)
+#define PMECR_WKEVT_MASK                       (0xf << 2)
+#define PMECR_WKEVT_SHIFT                      (2)
+#define PMECR_WKEVT_GET(_v)                    (((_v) >> 2) & 0xf)
+#define PMECR_WKEVT_ENERGY                     (0x1 << 2)
+#define PMECR_WKEVT_LINK                       (0x2 << 2)
+#define PMECR_WKEVT_MAGICPKT                   (0x4 << 2)
+#define PMECR_WKEVT_FRAME                      (0x8 << 2)
+#define PMECR_PM_MASK                          (0x3 << 0)
+#define PMECR_PM_SHIFT                         (0)
+#define PMECR_PM_NORMAL                                (0x0 << 0)
+#define PMECR_PM_ENERGY                                (0x1 << 0)
+#define PMECR_PM_SOFTDOWN                      (0x2 << 0)
+#define PMECR_PM_POWERSAVE                     (0x3 << 0)
+
+/* Standard MII PHY data */
+#define KS_P1MBCR                              0xE4
+#define KS_P1MBSR                              0xE6
+#define KS_PHY1ILR                             0xE8
+#define KS_PHY1IHR                             0xEA
+#define KS_P1ANAR                              0xEC
+#define KS_P1ANLPR                             0xEE
+
+#define KS_P1SCLMD                             0xF4
+#define P1SCLMD_LEDOFF                         (1 << 15)
+#define P1SCLMD_TXIDS                          (1 << 14)
+#define P1SCLMD_RESTARTAN                      (1 << 13)
+#define P1SCLMD_DISAUTOMDIX                    (1 << 10)
+#define P1SCLMD_FORCEMDIX                      (1 << 9)
+#define P1SCLMD_AUTONEGEN                      (1 << 7)
+#define P1SCLMD_FORCE100                       (1 << 6)
+#define P1SCLMD_FORCEFDX                       (1 << 5)
+#define P1SCLMD_ADV_FLOW                       (1 << 4)
+#define P1SCLMD_ADV_100BT_FDX                  (1 << 3)
+#define P1SCLMD_ADV_100BT_HDX                  (1 << 2)
+#define P1SCLMD_ADV_10BT_FDX                   (1 << 1)
+#define P1SCLMD_ADV_10BT_HDX                   (1 << 0)
+
+#define KS_P1CR                                        0xF6
+#define P1CR_HP_MDIX                           (1 << 15)
+#define P1CR_REV_POL                           (1 << 13)
+#define P1CR_OP_100M                           (1 << 10)
+#define P1CR_OP_FDX                            (1 << 9)
+#define P1CR_OP_MDI                            (1 << 7)
+#define P1CR_AN_DONE                           (1 << 6)
+#define P1CR_LINK_GOOD                         (1 << 5)
+#define P1CR_PNTR_FLOW                         (1 << 4)
+#define P1CR_PNTR_100BT_FDX                    (1 << 3)
+#define P1CR_PNTR_100BT_HDX                    (1 << 2)
+#define P1CR_PNTR_10BT_FDX                     (1 << 1)
+#define P1CR_PNTR_10BT_HDX                     (1 << 0)
+
+/* TX Frame control */
+
+#define TXFR_TXIC                              (1 << 15)
+#define TXFR_TXFID_MASK                                (0x3f << 0)
+#define TXFR_TXFID_SHIFT                       (0)
+
+/* SPI frame opcodes */
+#define KS_SPIOP_RD                            (0x00)
+#define KS_SPIOP_WR                            (0x40)
+#define KS_SPIOP_RXFIFO                                (0x80)
+#define KS_SPIOP_TXFIFO                                (0xC0)
index acd143da161d5da4a6e757e10c8b6a9a4e2bc809..61eabcac734cdbce1de299924867858740a92ac3 100644 (file)
@@ -179,7 +179,7 @@ static const struct net_device_ops macsonic_netdev_ops = {
        .ndo_set_mac_address    = eth_mac_addr,
 };
 
-static int __init macsonic_init(struct net_device *dev)
+static int __devinit macsonic_init(struct net_device *dev)
 {
        struct sonic_local* lp = netdev_priv(dev);
 
@@ -223,7 +223,7 @@ static int __init macsonic_init(struct net_device *dev)
        return 0;
 }
 
-static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev)
+static int __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev)
 {
        struct sonic_local *lp = netdev_priv(dev);
        const int prom_addr = ONBOARD_SONIC_PROM_BASE;
@@ -288,7 +288,7 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev)
        } else return 0;
 }
 
-static int __init mac_onboard_sonic_probe(struct net_device *dev)
+static int __devinit mac_onboard_sonic_probe(struct net_device *dev)
 {
        /* Bwahahaha */
        static int once_is_more_than_enough;
@@ -409,7 +409,7 @@ static int __init mac_onboard_sonic_probe(struct net_device *dev)
        return macsonic_init(dev);
 }
 
-static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev,
+static int __devinit mac_nubus_sonic_ethernet_addr(struct net_device *dev,
                                                unsigned long prom_addr,
                                                int id)
 {
@@ -424,7 +424,7 @@ static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev,
        return 0;
 }
 
-static int __init macsonic_ident(struct nubus_dev *ndev)
+static int __devinit macsonic_ident(struct nubus_dev *ndev)
 {
        if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
            ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
@@ -449,7 +449,7 @@ static int __init macsonic_ident(struct nubus_dev *ndev)
        return -1;
 }
 
-static int __init mac_nubus_sonic_probe(struct net_device *dev)
+static int __devinit mac_nubus_sonic_probe(struct net_device *dev)
 {
        static int slots;
        struct nubus_dev* ndev = NULL;
@@ -562,7 +562,7 @@ static int __init mac_nubus_sonic_probe(struct net_device *dev)
        return macsonic_init(dev);
 }
 
-static int __init mac_sonic_probe(struct platform_device *pdev)
+static int __devinit mac_sonic_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct sonic_local *lp;
@@ -575,6 +575,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev)
        lp = netdev_priv(dev);
        lp->device = &pdev->dev;
        SET_NETDEV_DEV(dev, &pdev->dev);
+       platform_set_drvdata(pdev, dev);
 
        /* This will catch fatal stuff like -ENOMEM as well as success */
        err = mac_onboard_sonic_probe(dev);
index 2845a0560b84e18fcd28c64e9caa145b59c9a034..65ec77dc31f5b5c4a542a22a2f7d11c464a9d664 100644 (file)
@@ -80,7 +80,9 @@ enum {
        /* Bad management packet (silently discarded): */
        CMD_STAT_BAD_PKT        = 0x30,
        /* More outstanding CQEs in CQ than new CQ size: */
-       CMD_STAT_BAD_SIZE       = 0x40
+       CMD_STAT_BAD_SIZE       = 0x40,
+       /* Multi Function device support required: */
+       CMD_STAT_MULTI_FUNC_REQ = 0x50,
 };
 
 enum {
@@ -128,6 +130,7 @@ static int mlx4_status_to_errno(u8 status)
                [CMD_STAT_LAM_NOT_PRE]    = -EAGAIN,
                [CMD_STAT_BAD_PKT]        = -EINVAL,
                [CMD_STAT_BAD_SIZE]       = -ENOMEM,
+               [CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
        };
 
        if (status >= ARRAY_SIZE(trans_table) ||
index 091f99052c91673f4536004e885cdebca05f598c..86467b444ac679ab4b4a62e25aaba29c38d12bf2 100644 (file)
@@ -220,7 +220,7 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        cmd->autoneg = AUTONEG_DISABLE;
        cmd->supported = SUPPORTED_10000baseT_Full;
-       cmd->advertising = SUPPORTED_10000baseT_Full;
+       cmd->advertising = ADVERTISED_1000baseT_Full;
        if (netif_carrier_ok(dev)) {
                cmd->speed = SPEED_10000;
                cmd->duplex = DUPLEX_FULL;
index 018348c011933b1240153f24ee95ba836c83c22c..dac621b1e9fc9a287fb8b4f7fdfa4f538ecc2a77 100644 (file)
@@ -729,7 +729,10 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 
        err = mlx4_QUERY_FW(dev);
        if (err) {
-               mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
+               if (err == -EACCES)
+                       mlx4_info(dev, "non-primary physical function, skipping.\n");
+               else
+                       mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
                return err;
        }
 
@@ -1285,6 +1288,7 @@ static struct pci_device_id mlx4_pci_table[] = {
        { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */
        { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */
        { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */
+       { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
        { 0, }
 };
 
index e1cdba752e09daa397c331b9c5708da267d8a7d9..f86e05047d19db0bdd56feb1b726373fcbeee733 100644 (file)
 #define NETXEN_CTX_SIGNATURE   0xdee0
 #define NETXEN_CTX_SIGNATURE_V2        0x0002dee0
 #define NETXEN_CTX_RESET       0xbad0
+#define NETXEN_CTX_D3_RESET    0xacc0
 #define NETXEN_RCV_PRODUCER(ringid)    (ringid)
 
 #define PHAN_PEG_RCV_INITIALIZED       0xff01
@@ -773,6 +774,8 @@ struct nx_host_tx_ring {
        u32 crb_cmd_consumer;
        u32 num_desc;
 
+       struct netdev_queue *txq;
+
        struct netxen_cmd_buffer *cmd_buf_arr;
        struct cmd_desc_type0 *desc_head;
        dma_addr_t phys_addr;
index 4754f5cffad078ce53436b26330b6a0623ee4749..9f8ae4719e2fb4a9d91d4893db5baf675ccd7616 100644 (file)
@@ -684,10 +684,8 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
                        goto err_out_free;
        } else {
                err = netxen_init_old_ctx(adapter);
-               if (err) {
-                       netxen_free_hw_resources(adapter);
-                       return err;
-               }
+               if (err)
+                       goto err_out_free;
        }
 
        return 0;
@@ -708,15 +706,18 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
        int port = adapter->portnum;
 
        if (adapter->fw_major >= 4) {
-               nx_fw_cmd_destroy_tx_ctx(adapter);
                nx_fw_cmd_destroy_rx_ctx(adapter);
+               nx_fw_cmd_destroy_tx_ctx(adapter);
        } else {
                netxen_api_lock(adapter);
                NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port),
-                               NETXEN_CTX_RESET | port);
+                               NETXEN_CTX_D3_RESET | port);
                netxen_api_unlock(adapter);
        }
 
+       /* Allow dma queues to drain after context reset */
+       msleep(20);
+
        recv_ctx = &adapter->recv_ctx;
 
        if (recv_ctx->hwctx != NULL) {
index ce3b89d2cbb6c11e3ab5749446bec617dcc4edeb..b9123d445c966bbfc2ae7dc7e6f7e9ec46b9711c 100644 (file)
@@ -461,13 +461,14 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
        i = 0;
 
        tx_ring = adapter->tx_ring;
-       netif_tx_lock_bh(adapter->netdev);
+       __netif_tx_lock_bh(tx_ring->txq);
 
        producer = tx_ring->producer;
        consumer = tx_ring->sw_consumer;
 
-       if (nr_desc >= find_diff_among(producer, consumer, tx_ring->num_desc)) {
-               netif_tx_unlock_bh(adapter->netdev);
+       if (nr_desc >= netxen_tx_avail(tx_ring)) {
+               netif_tx_stop_queue(tx_ring->txq);
+               __netif_tx_unlock_bh(tx_ring->txq);
                return -EBUSY;
        }
 
@@ -490,7 +491,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
 
        netxen_nic_update_cmd_producer(adapter, tx_ring);
 
-       netif_tx_unlock_bh(adapter->netdev);
+       __netif_tx_unlock_bh(tx_ring->txq);
 
        return 0;
 }
index b899bd51fcd87e2563fa4fd495b8c760fe5c0e6d..7acf204e38c9261b0168b4828a85f61bbc87eb47 100644 (file)
@@ -184,6 +184,13 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter)
        kfree(recv_ctx->rds_rings);
 
 skip_rds:
+       if (recv_ctx->sds_rings == NULL)
+               goto skip_sds;
+
+       for(ring = 0; ring < adapter->max_sds_rings; ring++)
+               recv_ctx->sds_rings[ring].consumer = 0;
+
+skip_sds:
        if (adapter->tx_ring == NULL)
                return;
 
@@ -214,6 +221,7 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
        adapter->tx_ring = tx_ring;
 
        tx_ring->num_desc = adapter->num_txd;
+       tx_ring->txq = netdev_get_tx_queue(netdev, 0);
 
        cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
        if (cmd_buf_arr == NULL) {
@@ -1400,10 +1408,10 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
                smp_mb();
 
                if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
-                       netif_tx_lock(netdev);
+                       __netif_tx_lock(tx_ring->txq, smp_processor_id());
                        if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH)
                                netif_wake_queue(netdev);
-                       netif_tx_unlock(netdev);
+                       __netif_tx_unlock(tx_ring->txq);
                }
        }
        /*
index 27539ddf94c4f9304c8310e652c1ee7f120f78af..637ac8b89bac3e530962ae111bc0329d53c71bf6 100644 (file)
@@ -215,9 +215,9 @@ netxen_napi_disable(struct netxen_adapter *adapter)
 
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
-               napi_disable(&sds_ring->napi);
                netxen_nic_disable_int(sds_ring);
-               synchronize_irq(sds_ring->irq);
+               napi_synchronize(&sds_ring->napi);
+               napi_disable(&sds_ring->napi);
        }
 }
 
@@ -833,11 +833,11 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
 
        adapter->ahw.linkup = 0;
 
-       netxen_napi_enable(adapter);
-
        if (adapter->max_sds_rings > 1)
                netxen_config_rss(adapter, 1);
 
+       netxen_napi_enable(adapter);
+
        if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION)
                netxen_linkevent_request(adapter, 1);
        else
@@ -851,8 +851,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
 static void
 netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev)
 {
+       spin_lock(&adapter->tx_clean_lock);
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
+       netif_tx_disable(netdev);
 
        if (adapter->stop_port)
                adapter->stop_port(adapter);
@@ -863,9 +864,10 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev)
        netxen_napi_disable(adapter);
 
        netxen_release_tx_buffers(adapter);
+       spin_unlock(&adapter->tx_clean_lock);
 
-       FLUSH_SCHEDULED_WORK();
        del_timer_sync(&adapter->watchdog_timer);
+       FLUSH_SCHEDULED_WORK();
 }
 
 
@@ -943,8 +945,8 @@ err_out_free_sw:
 static void
 netxen_nic_detach(struct netxen_adapter *adapter)
 {
-       netxen_release_rx_buffers(adapter);
        netxen_free_hw_resources(adapter);
+       netxen_release_rx_buffers(adapter);
        netxen_nic_free_irq(adapter);
        netxen_free_sw_resources(adapter);
 
@@ -1533,10 +1535,12 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter)
                printk(KERN_ALERT
                       "%s: Device temperature %d degrees C exceeds"
                       " maximum allowed. Hardware has been shut down.\n",
-                      netxen_nic_driver_name, temp_val);
+                      netdev->name, temp_val);
+
+               netif_device_detach(netdev);
+               netxen_nic_down(adapter, netdev);
+               netxen_nic_detach(adapter);
 
-               netif_carrier_off(netdev);
-               netif_stop_queue(netdev);
                rv = 1;
        } else if (temp_state == NX_TEMP_WARN) {
                if (adapter->temp == NX_TEMP_NORMAL) {
@@ -1544,13 +1548,13 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter)
                               "%s: Device temperature %d degrees C "
                               "exceeds operating range."
                               " Immediate action needed.\n",
-                              netxen_nic_driver_name, temp_val);
+                              netdev->name, temp_val);
                }
        } else {
                if (adapter->temp == NX_TEMP_WARN) {
                        printk(KERN_INFO
                               "%s: Device temperature is now %d degrees C"
-                              " in normal range.\n", netxen_nic_driver_name,
+                              " in normal range.\n", netdev->name,
                               temp_val);
                }
        }
@@ -1623,7 +1627,7 @@ void netxen_watchdog_task(struct work_struct *work)
        struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, watchdog_task);
 
-       if ((adapter->portnum  == 0) && netxen_nic_check_temp(adapter))
+       if (netxen_nic_check_temp(adapter))
                return;
 
        if (!adapter->has_link_events)
@@ -1645,6 +1649,9 @@ static void netxen_tx_timeout_task(struct work_struct *work)
        struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, tx_timeout_task);
 
+       if (!netif_running(adapter->netdev))
+               return;
+
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
               netxen_nic_driver_name, adapter->netdev->name);
 
@@ -1757,7 +1764,8 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
 
        if ((work_done < budget) && tx_complete) {
                napi_complete(&sds_ring->napi);
-               netxen_nic_enable_int(sds_ring);
+               if (netif_running(adapter->netdev))
+                       netxen_nic_enable_int(sds_ring);
        }
 
        return work_done;
index ec7cf5ac4f0595275551e3addecf16747be79c92..690b9c76d34ebf9f22772a727268e1441db4d92f 100644 (file)
@@ -156,6 +156,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev);
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static const struct ethtool_ops netdev_ethtool_ops;
 
@@ -488,8 +489,7 @@ static void tc589_reset(struct net_device *dev)
     /* Switch to register set 1 for normal use. */
     EL3WINDOW(1);
 
-    /* Accept b-cast and phys addr only. */
-    outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+    set_rx_mode(dev);
     outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
     outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
     outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -700,7 +700,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
                if (fifo_diag & 0x2000) {
                    /* Rx underrun */
                    tc589_wait_for_completion(dev, RxReset);
-                   set_multicast_list(dev);
+                   set_rx_mode(dev);
                    outw(RxEnable, ioaddr + EL3_CMD);
                }
                outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
@@ -905,14 +905,11 @@ static int el3_rx(struct net_device *dev)
     return 0;
 }
 
-static void set_multicast_list(struct net_device *dev)
+static void set_rx_mode(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
     unsigned int ioaddr = dev->base_addr;
     u16 opts = SetRxFilter | RxStation | RxBroadcast;
 
-    if (!pcmcia_dev_present(link)) return;
     if (dev->flags & IFF_PROMISC)
        opts |= RxMulticast | RxProm;
     else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
@@ -920,6 +917,16 @@ static void set_multicast_list(struct net_device *dev)
     outw(opts, ioaddr + EL3_CMD);
 }
 
+static void set_multicast_list(struct net_device *dev)
+{
+       struct el3_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       set_rx_mode(dev);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
 static int el3_close(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
index 33984b737233c8cb13d9d0dbf9a2e0d6d915601e..22cdd451fb822ca0e6f64d944e4fd8fa177da29c 100644 (file)
@@ -30,6 +30,7 @@
 
 #ifdef CONFIG_OF_GPIO
 #include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #endif
 
@@ -81,13 +82,12 @@ static struct mdiobb_ops mdio_gpio_ops = {
        .get_mdio_data = mdio_get,
 };
 
-static int __devinit mdio_gpio_bus_init(struct device *dev,
+static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
                                        struct mdio_gpio_platform_data *pdata,
                                        int bus_id)
 {
        struct mii_bus *new_bus;
        struct mdio_gpio_info *bitbang;
-       int ret = -ENOMEM;
        int i;
 
        bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
@@ -104,8 +104,6 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
 
        new_bus->name = "GPIO Bitbanged MDIO",
 
-       ret = -ENODEV;
-
        new_bus->phy_mask = pdata->phy_mask;
        new_bus->irq = pdata->irqs;
        new_bus->parent = dev;
@@ -129,15 +127,8 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
 
        dev_set_drvdata(dev, new_bus);
 
-       ret = mdiobus_register(new_bus);
-       if (ret)
-               goto out_free_all;
-
-       return 0;
+       return new_bus;
 
-out_free_all:
-       dev_set_drvdata(dev, NULL);
-       gpio_free(bitbang->mdio);
 out_free_mdc:
        gpio_free(bitbang->mdc);
 out_free_bus:
@@ -145,30 +136,47 @@ out_free_bus:
 out_free_bitbang:
        kfree(bitbang);
 out:
-       return ret;
+       return NULL;
 }
 
-static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+static void __devinit mdio_gpio_bus_deinit(struct device *dev)
 {
        struct mii_bus *bus = dev_get_drvdata(dev);
        struct mdio_gpio_info *bitbang = bus->priv;
 
-       mdiobus_unregister(bus);
-       free_mdio_bitbang(bus);
        dev_set_drvdata(dev, NULL);
-       gpio_free(bitbang->mdc);
        gpio_free(bitbang->mdio);
+       gpio_free(bitbang->mdc);
+       free_mdio_bitbang(bus);
        kfree(bitbang);
 }
 
+static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+{
+       struct mii_bus *bus = dev_get_drvdata(dev);
+
+       mdiobus_unregister(bus);
+       mdio_gpio_bus_deinit(dev);
+}
+
 static int __devinit mdio_gpio_probe(struct platform_device *pdev)
 {
        struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct mii_bus *new_bus;
+       int ret;
 
        if (!pdata)
                return -ENODEV;
 
-       return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+       new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+       if (!new_bus)
+               return -ENODEV;
+
+       ret = mdiobus_register(new_bus);
+       if (ret)
+               mdio_gpio_bus_deinit(&pdev->dev);
+
+       return ret;
 }
 
 static int __devexit mdio_gpio_remove(struct platform_device *pdev)
@@ -179,29 +187,12 @@ static int __devexit mdio_gpio_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF_GPIO
-static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
-                             struct device_node *np)
-{
-       const u32 *data;
-       int len, id, irq;
-
-       data = of_get_property(np, "reg", &len);
-       if (!data || len != 4)
-               return;
-
-       id = *data;
-       pdata->phy_mask &= ~(1 << id);
-
-       irq = of_irq_to_resource(np, 0, NULL);
-       if (irq)
-               pdata->irqs[id] = irq;
-}
 
 static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
                                         const struct of_device_id *match)
 {
-       struct device_node *np = NULL;
        struct mdio_gpio_platform_data *pdata;
+       struct mii_bus *new_bus;
        int ret;
 
        pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
@@ -215,14 +206,18 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
 
        ret = of_get_gpio(ofdev->node, 1);
        if (ret < 0)
-                goto out_free;
+               goto out_free;
        pdata->mdio = ret;
 
-       while ((np = of_get_next_child(ofdev->node, np)))
-               if (!strcmp(np->type, "ethernet-phy"))
-                       add_phy(pdata, np);
+       new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+       if (!new_bus)
+               return -ENODEV;
 
-       return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+       ret = of_mdiobus_register(new_bus, ofdev->node);
+       if (ret)
+               mdio_gpio_bus_deinit(&ofdev->dev);
+
+       return ret;
 
 out_free:
        kfree(pdata);
index eba937c463767fd1e07ea2425db0a17165e263ab..b10fedd8214394b591bfb81bd102c8d38fce9fb1 100644 (file)
@@ -134,8 +134,10 @@ int phy_scan_fixups(struct phy_device *phydev)
 
                        err = fixup->run(phydev);
 
-                       if (err < 0)
+                       if (err < 0) {
+                               mutex_unlock(&phy_fixup_lock);
                                return err;
+                       }
                }
        }
        mutex_unlock(&phy_fixup_lock);
index 7a62f781fef2b83fdfe55dc0cad944cb5a2d7c8b..2ca8b0d84ee2d7f2647e3064e6f1615f116c1294 100644 (file)
@@ -270,6 +270,9 @@ static const struct net_device_ops plip_netdev_ops = {
        .ndo_stop                = plip_close,
        .ndo_start_xmit          = plip_tx_packet,
        .ndo_do_ioctl            = plip_ioctl,
+       .ndo_change_mtu          = eth_change_mtu,
+       .ndo_set_mac_address     = eth_mac_addr,
+       .ndo_validate_addr       = eth_validate_addr,
 };
 
 /* Entry point of PLIP driver.
index 17c116bb332c7e0c41da3f97aeb3ac3755097e87..6de8399d6dd92d26875cca679ec332c19082d736 100644 (file)
@@ -356,6 +356,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        if (!skb_queue_empty(&ap->rqueue))
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
+       tty_unthrottle(tty);
 }
 
 static void
index aa3d39f38e2257deee5e72e9df06453be96e3046..d2fa2db1358633771439013546758654444c6a00 100644 (file)
@@ -397,6 +397,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
        if (!skb_queue_empty(&ap->rqueue))
                tasklet_schedule(&ap->tsk);
        sp_put(ap);
+       tty_unthrottle(tty);
 }
 
 static void
index d1a5fb4d6acb1e63e479abea8db9a1e1f4a3e5f7..a3932c9f3406c9d4e75967fc392d759cffb78330 100644 (file)
@@ -1411,6 +1411,7 @@ static const struct net_device_ops gelic_netdevice_ops = {
        .ndo_set_multicast_list = gelic_net_set_multi,
        .ndo_change_mtu = gelic_net_change_mtu,
        .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gelic_net_poll_controller,
index b6b3ca9bdb213a9fa995b35cda8cc72f0cf480d2..6932b08d746b38b1c830d3ea3f720496562e9129 100644 (file)
@@ -2707,6 +2707,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = {
        .ndo_set_multicast_list = gelic_net_set_multi,
        .ndo_change_mtu = gelic_net_change_mtu,
        .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = gelic_net_poll_controller,
index ed63d23a645233f9da9a6e88abb51632fdf5f98d..961b5397a531ea3800ccf43ac4f9b12a7e6849c2 100644 (file)
@@ -49,8 +49,8 @@
 #include <asm/processor.h>
 
 #define DRV_NAME       "r6040"
-#define DRV_VERSION    "0.23"
-#define DRV_RELDATE    "05May2009"
+#define DRV_VERSION    "0.24"
+#define DRV_RELDATE    "08Jul2009"
 
 /* PHY CHIP Address */
 #define PHY1_ADDR      1       /* For MAC1 */
@@ -704,8 +704,11 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id)
        /* Read MISR status and clear */
        status = ioread16(ioaddr + MISR);
 
-       if (status == 0x0000 || status == 0xffff)
+       if (status == 0x0000 || status == 0xffff) {
+               /* Restore RDC MAC interrupt */
+               iowrite16(misr, ioaddr + MIER);
                return IRQ_NONE;
+       }
 
        /* RX interrupt request */
        if (status & RX_INTS) {
index 4b53b58d75fc0375e03579e79c9dbb5adf808056..b82780d805f544c50b341ed1f34f07f41e400c99 100644 (file)
@@ -2060,8 +2060,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       pci_set_master(pdev);
-
        /* ioremap MMIO region */
        ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
        if (!ioaddr) {
@@ -2089,6 +2087,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        RTL_W16(IntrStatus, 0xffff);
 
+       pci_set_master(pdev);
+
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
 
@@ -3874,6 +3874,15 @@ static void rtl_shutdown(struct pci_dev *pdev)
        spin_unlock_irq(&tp->lock);
 
        if (system_state == SYSTEM_POWER_OFF) {
+               /* WoL fails with some 8168 when the receiver is disabled. */
+               if (tp->features & RTL_FEATURE_WOL) {
+                       pci_clear_master(pdev);
+
+                       RTL_W8(ChipCmd, CmdRxEnb);
+                       /* PCI commit */
+                       RTL_R8(ChipCmd);
+               }
+
                pci_wake_from_d3(pdev, true);
                pci_set_power_state(pdev, PCI_D3hot);
        }
index 18821f217e19fa286a732973cfc917463638e672..e3156c97bb58b5a163a5c8f6531cbf8b842a4201 100644 (file)
@@ -1593,6 +1593,7 @@ out:
 static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
        { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) },
        { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) },
+       { PCI_DEVICE(0x1088, 0x2031) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
index 60d502eef4fc36868d6fac2099f14ec852855497..543af2044f40df39eea68d5eef6608dc1847613a 100644 (file)
@@ -3854,8 +3854,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        skge->speed = -1;
        skge->advertising = skge_supported_modes(hw);
 
-       if (device_may_wakeup(&hw->pdev->dev))
+       if (device_can_wakeup(&hw->pdev->dev)) {
                skge->wol = wol_supported(hw) & WAKE_MAGIC;
+               device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+       }
 
        hw->dev[port] = dev;
 
index daf961ab68bc27e3fa16ddea89784aa0091b42e2..3550c5dcd93c599ed2e91f4424821c87523c76fb 100644 (file)
@@ -1151,14 +1151,7 @@ stopped:
 
        /* reset the Rx prefetch unit */
        sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
-
-       /* Reset the RAM Buffer receive queue */
-       sky2_write8(hw, RB_ADDR(rxq, RB_CTRL), RB_RST_SET);
-
-       /* Reset Rx MAC FIFO */
-       sky2_write8(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), GMF_RST_SET);
-
-       sky2_read8(hw, B0_CTST);
+       mmiowb();
 }
 
 /* Clean out receive buffer area, assumes receiver hardware stopped */
@@ -1825,12 +1818,6 @@ static int sky2_down(struct net_device *dev)
        if (netif_msg_ifdown(sky2))
                printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
 
-       /* Disable port IRQ */
-       imask = sky2_read32(hw, B0_IMSK);
-       imask &= ~portirq_msk[port];
-       sky2_write32(hw, B0_IMSK, imask);
-       sky2_read32(hw, B0_IMSK);
-
        /* Force flow control off */
        sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
 
@@ -1870,8 +1857,6 @@ static int sky2_down(struct net_device *dev)
 
        sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET);
 
-       sky2_rx_stop(sky2);
-
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
 
@@ -1881,6 +1866,14 @@ static int sky2_down(struct net_device *dev)
        sky2_write32(hw, STAT_ISR_TIMER_CNT, 0);
        sky2_read8(hw, STAT_ISR_TIMER_CTRL);
 
+       sky2_rx_stop(sky2);
+
+       /* Disable port IRQ */
+       imask = sky2_read32(hw, B0_IMSK);
+       imask &= ~portirq_msk[port];
+       sky2_write32(hw, B0_IMSK, imask);
+       sky2_read32(hw, B0_IMSK);
+
        synchronize_irq(hw->pdev->irq);
        napi_synchronize(&hw->napi);
 
index fdcbaf8dfa739618a5a8f25bc27f6c24222e8004..1c70e999cc50d866ab5ebdba0956b25bba83659d 100644 (file)
@@ -1774,6 +1774,7 @@ static const struct net_device_ops smc_netdev_ops = {
        .ndo_start_xmit         = smc_hard_start_xmit,
        .ndo_tx_timeout         = smc_timeout,
        .ndo_set_multicast_list = smc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
index f1f773b17fe121fc09f68eb84325a01b304bd87f..57a159fac99fcc1308ae106e06aadb7602bfe496 100644 (file)
@@ -186,7 +186,8 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
 #define SMC_IRQ_FLAGS          (-1)    /* from resource */
 
-#elif  defined(CONFIG_MACH_LOGICPD_PXA270)
+#elif  defined(CONFIG_MACH_LOGICPD_PXA270) \
+       || defined(CONFIG_MACH_NOMADIK_8815NHK)
 
 #define SMC_CAN_USE_8BIT       0
 #define SMC_CAN_USE_16BIT      1
index 66067f9d91c05499264762c8f0a4600351b7e8e5..94b6d2658ddc016cea883126e276bbf4c0c936bf 100644 (file)
@@ -1779,6 +1779,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
        .ndo_get_stats          = smsc911x_get_stats,
        .ndo_set_multicast_list = smsc911x_set_multicast_list,
        .ndo_do_ioctl           = smsc911x_do_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = smsc911x_set_mac_address,
 #ifdef CONFIG_NET_POLL_CONTROLLER
index a82fb2aca4cb7d89fe52e8bb31dfe4b6eacac505..f1e5e4542c2a04084b419c990e67760e05253f82 100644 (file)
@@ -1016,7 +1016,9 @@ static const struct net_device_ops vnet_ops = {
        .ndo_open               = vnet_open,
        .ndo_stop               = vnet_close,
        .ndo_set_multicast_list = vnet_set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
        .ndo_set_mac_address    = vnet_set_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = vnet_tx_timeout,
        .ndo_change_mtu         = vnet_change_mtu,
        .ndo_start_xmit         = vnet_start_xmit,
index 9d896116cf761b6aea8a6b294a2da95fa07238f5..08a6c41c1599f067ac8c165ab4c9efab309170b2 100644 (file)
@@ -1912,7 +1912,7 @@ static int __init ibmtr_init(void)
 
        find_turbo_adapters(io);
 
-       for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) {
+       for (i = 0; i < IBMTR_MAX_ADAPTERS && io[i]; i++) {
                struct net_device *dev;
                irq[i] = 0;
                mem[i] = 0;
index 40c6eba775ce89c026f218ff27f97445f4b7fe02..3b957e6412ee7bfab7de95f7554fbf1112cab739 100644 (file)
@@ -1590,13 +1590,13 @@ static int init_phy(struct net_device *dev)
        priv->oldspeed = 0;
        priv->oldduplex = -1;
 
-       if (!ug_info->phy_node)
-               return 0;
-
        phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
                                priv->phy_interface);
+       if (!phydev)
+               phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+                                                  priv->phy_interface);
        if (!phydev) {
-               printk("%s: Could not attach to PHY\n", dev->name);
+               dev_err(&dev->dev, "Could not attach to PHY\n");
                return -ENODEV;
        }
 
@@ -3608,9 +3608,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        struct ucc_geth_private *ugeth = NULL;
        struct ucc_geth_info *ug_info;
        struct resource res;
-       struct device_node *phy;
        int err, ucc_num, max_speed = 0;
-       const u32 *fixed_link;
        const unsigned int *prop;
        const char *sprop;
        const void *mac_addr;
@@ -3708,15 +3706,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 
        ug_info->uf_info.regs = res.start;
        ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
-       fixed_link = of_get_property(np, "fixed-link", NULL);
-       if (fixed_link) {
-               phy = NULL;
-       } else {
-               phy = of_parse_phandle(np, "phy-handle", 0);
-               if (phy == NULL)
-                       return -ENODEV;
-       }
-       ug_info->phy_node = phy;
+
+       ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
        /* Find the TBI PHY node.  If it's not there, we don't support SGMII */
        ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -3725,7 +3716,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        prop = of_get_property(np, "phy-connection-type", NULL);
        if (!prop) {
                /* handle interface property present in old trees */
-               prop = of_get_property(phy, "interface", NULL);
+               prop = of_get_property(ug_info->phy_node, "interface", NULL);
                if (prop != NULL) {
                        phy_interface = enet_to_phy_interface[*prop];
                        max_speed = enet_to_speed[*prop];
index a906d3998131a512b0f125f3f8892cf38c3bdaf5..c47237c2d638ef97dc3a2d10186c0cdf55e9c452 100644 (file)
@@ -369,4 +369,12 @@ config USB_NET_INT51X1
          (Powerline Communications) solution with an Intellon
          INT51x1/INT5200 chip, like the "devolo dLan duo".
 
+config USB_CDC_PHONET
+       tristate "CDC Phonet support"
+       depends on PHONET
+       help
+         Choose this option to support the Phonet interface to a Nokia
+         cellular modem, as found on most Nokia handsets with the
+         "PC suite" USB profile.
+
 endmenu
index b870b0b1cbe0a1280ad7900a05c148417ff7729f..e17afb78f37220df2c8c6a13eb420aa14280fd09 100644 (file)
@@ -21,4 +21,5 @@ obj-$(CONFIG_USB_NET_ZAURUS)  += zaurus.o
 obj-$(CONFIG_USB_NET_MCS7830)  += mcs7830.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
 obj-$(CONFIG_USB_NET_INT51X1)  += int51x1.o
+obj-$(CONFIG_USB_CDC_PHONET)   += cdc-phonet.o
 
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
new file mode 100644 (file)
index 0000000..792af72
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * phonet.c -- USB CDC Phonet host driver
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
+ *
+ * Author: Rémi Denis-Courmont
+ *
+ * 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/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_phonet.h>
+
+#define PN_MEDIA_USB   0x1B
+
+static const unsigned rxq_size = 17;
+
+struct usbpn_dev {
+       struct net_device       *dev;
+
+       struct usb_interface    *intf, *data_intf;
+       struct usb_device       *usb;
+       unsigned int            tx_pipe, rx_pipe;
+       u8 active_setting;
+       u8 disconnected;
+
+       unsigned                tx_queue;
+       spinlock_t              tx_lock;
+
+       spinlock_t              rx_lock;
+       struct sk_buff          *rx_skb;
+       struct urb              *urbs[0];
+};
+
+static void tx_complete(struct urb *req);
+static void rx_complete(struct urb *req);
+
+/*
+ * Network device callbacks
+ */
+static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct usbpn_dev *pnd = netdev_priv(dev);
+       struct urb *req = NULL;
+       unsigned long flags;
+       int err;
+
+       if (skb->protocol != htons(ETH_P_PHONET))
+               goto drop;
+
+       req = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!req)
+               goto drop;
+       usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
+                               tx_complete, skb);
+       req->transfer_flags = URB_ZERO_PACKET;
+       err = usb_submit_urb(req, GFP_ATOMIC);
+       if (err) {
+               usb_free_urb(req);
+               goto drop;
+       }
+
+       spin_lock_irqsave(&pnd->tx_lock, flags);
+       pnd->tx_queue++;
+       if (pnd->tx_queue >= dev->tx_queue_len)
+               netif_stop_queue(dev);
+       spin_unlock_irqrestore(&pnd->tx_lock, flags);
+       return 0;
+
+drop:
+       dev_kfree_skb(skb);
+       dev->stats.tx_dropped++;
+       return 0;
+}
+
+static void tx_complete(struct urb *req)
+{
+       struct sk_buff *skb = req->context;
+       struct net_device *dev = skb->dev;
+       struct usbpn_dev *pnd = netdev_priv(dev);
+
+       switch (req->status) {
+       case 0:
+               dev->stats.tx_bytes += skb->len;
+               break;
+
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               dev->stats.tx_aborted_errors++;
+       default:
+               dev->stats.tx_errors++;
+               dev_dbg(&dev->dev, "TX error (%d)\n", req->status);
+       }
+       dev->stats.tx_packets++;
+
+       spin_lock(&pnd->tx_lock);
+       pnd->tx_queue--;
+       netif_wake_queue(dev);
+       spin_unlock(&pnd->tx_lock);
+
+       dev_kfree_skb_any(skb);
+       usb_free_urb(req);
+}
+
+static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
+{
+       struct net_device *dev = pnd->dev;
+       struct page *page;
+       int err;
+
+       page = __netdev_alloc_page(dev, gfp_flags);
+       if (!page)
+               return -ENOMEM;
+
+       usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
+                               PAGE_SIZE, rx_complete, dev);
+       req->transfer_flags = 0;
+       err = usb_submit_urb(req, gfp_flags);
+       if (unlikely(err)) {
+               dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
+               netdev_free_page(dev, page);
+       }
+       return err;
+}
+
+static void rx_complete(struct urb *req)
+{
+       struct net_device *dev = req->context;
+       struct usbpn_dev *pnd = netdev_priv(dev);
+       struct page *page = virt_to_page(req->transfer_buffer);
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       switch (req->status) {
+       case 0:
+               spin_lock_irqsave(&pnd->rx_lock, flags);
+               skb = pnd->rx_skb;
+               if (!skb) {
+                       skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
+                       if (likely(skb)) {
+                               /* Can't use pskb_pull() on page in IRQ */
+                               memcpy(skb_put(skb, 1), page_address(page), 1);
+                               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+                                               page, 1, req->actual_length);
+                               page = NULL;
+                       }
+               } else {
+                       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+                                       page, 0, req->actual_length);
+                       page = NULL;
+               }
+               if (req->actual_length < PAGE_SIZE)
+                       pnd->rx_skb = NULL; /* Last fragment */
+               else
+                       skb = NULL;
+               spin_unlock_irqrestore(&pnd->rx_lock, flags);
+               if (skb) {
+                       skb->protocol = htons(ETH_P_PHONET);
+                       skb_reset_mac_header(skb);
+                       __skb_pull(skb, 1);
+                       skb->dev = dev;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += skb->len;
+
+                       netif_rx(skb);
+               }
+               goto resubmit;
+
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               req = NULL;
+               break;
+
+       case -EOVERFLOW:
+               dev->stats.rx_over_errors++;
+               dev_dbg(&dev->dev, "RX overflow\n");
+               break;
+
+       case -EILSEQ:
+               dev->stats.rx_crc_errors++;
+               break;
+       }
+
+       dev->stats.rx_errors++;
+resubmit:
+       if (page)
+               netdev_free_page(dev, page);
+       if (req)
+               rx_submit(pnd, req, GFP_ATOMIC);
+}
+
+static int usbpn_close(struct net_device *dev);
+
+static int usbpn_open(struct net_device *dev)
+{
+       struct usbpn_dev *pnd = netdev_priv(dev);
+       int err;
+       unsigned i;
+       unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
+
+       err = usb_set_interface(pnd->usb, num, pnd->active_setting);
+       if (err)
+               return err;
+
+       for (i = 0; i < rxq_size; i++) {
+               struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
+
+               if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
+                       usbpn_close(dev);
+                       return -ENOMEM;
+               }
+               pnd->urbs[i] = req;
+       }
+
+       netif_wake_queue(dev);
+       return 0;
+}
+
+static int usbpn_close(struct net_device *dev)
+{
+       struct usbpn_dev *pnd = netdev_priv(dev);
+       unsigned i;
+       unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
+
+       netif_stop_queue(dev);
+
+       for (i = 0; i < rxq_size; i++) {
+               struct urb *req = pnd->urbs[i];
+
+               if (!req)
+                       continue;
+               usb_kill_urb(req);
+               usb_free_urb(req);
+               pnd->urbs[i] = NULL;
+       }
+
+       return usb_set_interface(pnd->usb, num, !pnd->active_setting);
+}
+
+static int usbpn_set_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static const struct net_device_ops usbpn_ops = {
+       .ndo_open       = usbpn_open,
+       .ndo_stop       = usbpn_close,
+       .ndo_start_xmit = usbpn_xmit,
+       .ndo_change_mtu = usbpn_set_mtu,
+};
+
+static void usbpn_setup(struct net_device *dev)
+{
+       dev->features           = 0;
+       dev->netdev_ops         = &usbpn_ops,
+       dev->header_ops         = &phonet_header_ops;
+       dev->type               = ARPHRD_PHONET;
+       dev->flags              = IFF_POINTOPOINT | IFF_NOARP;
+       dev->mtu                = PHONET_MAX_MTU;
+       dev->hard_header_len    = 1;
+       dev->dev_addr[0]        = PN_MEDIA_USB;
+       dev->addr_len           = 1;
+       dev->tx_queue_len       = 3;
+
+       dev->destructor         = free_netdev;
+}
+
+/*
+ * USB driver callbacks
+ */
+static struct usb_device_id usbpn_ids[] = {
+       {
+               .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+                       | USB_DEVICE_ID_MATCH_INT_CLASS
+                       | USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+               .idVendor = 0x0421, /* Nokia */
+               .bInterfaceClass = USB_CLASS_COMM,
+               .bInterfaceSubClass = 0xFE,
+       },
+       { },
+};
+
+MODULE_DEVICE_TABLE(usb, usbpn_ids);
+
+static struct usb_driver usbpn_driver;
+
+int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       static const char ifname[] = "usbpn%d";
+       const struct usb_cdc_union_desc *union_header = NULL;
+       const struct usb_cdc_header_desc *phonet_header = NULL;
+       const struct usb_host_interface *data_desc;
+       struct usb_interface *data_intf;
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct net_device *dev;
+       struct usbpn_dev *pnd;
+       u8 *data;
+       int len, err;
+
+       data = intf->altsetting->extra;
+       len = intf->altsetting->extralen;
+       while (len >= 3) {
+               u8 dlen = data[0];
+               if (dlen < 3)
+                       return -EINVAL;
+
+               /* bDescriptorType */
+               if (data[1] == USB_DT_CS_INTERFACE) {
+                       /* bDescriptorSubType */
+                       switch (data[2]) {
+                       case USB_CDC_UNION_TYPE:
+                               if (union_header || dlen < 5)
+                                       break;
+                               union_header =
+                                       (struct usb_cdc_union_desc *)data;
+                               break;
+                       case 0xAB:
+                               if (phonet_header || dlen < 5)
+                                       break;
+                               phonet_header =
+                                       (struct usb_cdc_header_desc *)data;
+                               break;
+                       }
+               }
+               data += dlen;
+               len -= dlen;
+       }
+
+       if (!union_header || !phonet_header)
+               return -EINVAL;
+
+       data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
+       if (data_intf == NULL)
+               return -ENODEV;
+       /* Data interface has one inactive and one active setting */
+       if (data_intf->num_altsetting != 2)
+               return -EINVAL;
+       if (data_intf->altsetting[0].desc.bNumEndpoints == 0
+        && data_intf->altsetting[1].desc.bNumEndpoints == 2)
+               data_desc = data_intf->altsetting + 1;
+       else
+       if (data_intf->altsetting[0].desc.bNumEndpoints == 2
+        && data_intf->altsetting[1].desc.bNumEndpoints == 0)
+               data_desc = data_intf->altsetting;
+       else
+               return -EINVAL;
+
+       dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
+                               ifname, usbpn_setup);
+       if (!dev)
+               return -ENOMEM;
+
+       pnd = netdev_priv(dev);
+       SET_NETDEV_DEV(dev, &intf->dev);
+       netif_stop_queue(dev);
+
+       pnd->dev = dev;
+       pnd->usb = usb_get_dev(usbdev);
+       pnd->intf = intf;
+       pnd->data_intf = data_intf;
+       spin_lock_init(&pnd->tx_lock);
+       spin_lock_init(&pnd->rx_lock);
+       /* Endpoints */
+       if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
+               pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
+                       data_desc->endpoint[0].desc.bEndpointAddress);
+               pnd->tx_pipe = usb_sndbulkpipe(usbdev,
+                       data_desc->endpoint[1].desc.bEndpointAddress);
+       } else {
+               pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
+                       data_desc->endpoint[1].desc.bEndpointAddress);
+               pnd->tx_pipe = usb_sndbulkpipe(usbdev,
+                       data_desc->endpoint[0].desc.bEndpointAddress);
+       }
+       pnd->active_setting = data_desc - data_intf->altsetting;
+
+       err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
+       if (err)
+               goto out;
+
+       /* Force inactive mode until the network device is brought UP */
+       usb_set_interface(usbdev, union_header->bSlaveInterface0,
+                               !pnd->active_setting);
+       usb_set_intfdata(intf, pnd);
+
+       err = register_netdev(dev);
+       if (err) {
+               usb_driver_release_interface(&usbpn_driver, data_intf);
+               goto out;
+       }
+
+       dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
+       return 0;
+
+out:
+       usb_set_intfdata(intf, NULL);
+       free_netdev(dev);
+       return err;
+}
+
+static void usbpn_disconnect(struct usb_interface *intf)
+{
+       struct usbpn_dev *pnd = usb_get_intfdata(intf);
+       struct usb_device *usb = pnd->usb;
+
+       if (pnd->disconnected)
+               return;
+
+       pnd->disconnected = 1;
+       usb_driver_release_interface(&usbpn_driver,
+                       (pnd->intf == intf) ? pnd->data_intf : pnd->intf);
+       unregister_netdev(pnd->dev);
+       usb_put_dev(usb);
+}
+
+static struct usb_driver usbpn_driver = {
+       .name =         "cdc_phonet",
+       .probe =        usbpn_probe,
+       .disconnect =   usbpn_disconnect,
+       .id_table =     usbpn_ids,
+};
+
+static int __init usbpn_init(void)
+{
+       return usb_register(&usbpn_driver);
+}
+
+static void __exit usbpn_exit(void)
+{
+       usb_deregister(&usbpn_driver);
+}
+
+module_init(usbpn_init);
+module_exit(usbpn_exit);
+
+MODULE_AUTHOR("Remi Denis-Courmont");
+MODULE_DESCRIPTION("USB CDC Phonet host interface");
+MODULE_LICENSE("GPL");
index cd35d50e46d4686982f9b285c7967cfb00a381de..45cebfb302cf438e769f0865decbf9f86a0f90b8 100644 (file)
@@ -311,7 +311,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                         *      bmCRC = 0       : CRC = 0xDEADBEEF
                         */
                        if (header & BIT(14))
-                               crc2 = ~crc32_le(~0, skb2->data, len);
+                               crc2 = ~crc32_le(~0, skb2->data, skb2->len);
                        else
                                crc2 = 0xdeadbeef;
 
index e0131478971829902dd2f8e836f7b17d0d74aeda..1f9ec29fce5042fc3a17f16f4a1c0708b9e6e50c 100644 (file)
@@ -999,6 +999,9 @@ static const struct net_device_ops kaweth_netdev_ops = {
        .ndo_tx_timeout =               kaweth_tx_timeout,
        .ndo_set_multicast_list =       kaweth_set_rx_mode,
        .ndo_get_stats =                kaweth_netdev_stats,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
 };
 
 static int kaweth_probe(
index 73acbd244aa106493cbdf7c3474937ee44e370f1..631d269ac980a8bb75647875dd1770241a48f5ba 100644 (file)
@@ -1493,6 +1493,9 @@ static const struct net_device_ops pegasus_netdev_ops = {
        .ndo_set_multicast_list =       pegasus_set_multicast,
        .ndo_get_stats =                pegasus_netdev_stats,
        .ndo_tx_timeout =               pegasus_tx_timeout,
+       .ndo_change_mtu =               eth_change_mtu,
+       .ndo_set_mac_address =          eth_mac_addr,
+       .ndo_validate_addr =            eth_validate_addr,
 };
 
 static struct usb_driver pegasus_driver = {
index d3489a3c4c03b28907035181134c20ccb44b9233..88c30a58b4bda50d0b5fb610916365076cbdf1c5 100644 (file)
@@ -621,6 +621,7 @@ static const struct net_device_ops rhine_netdev_ops = {
        .ndo_start_xmit          = rhine_start_tx,
        .ndo_get_stats           = rhine_get_stats,
        .ndo_set_multicast_list  = rhine_set_rx_mode,
+       .ndo_change_mtu          = eth_change_mtu,
        .ndo_validate_addr       = eth_validate_addr,
        .ndo_set_mac_address     = eth_mac_addr,
        .ndo_do_ioctl            = netdev_ioctl,
index d26e7b4853156dda0cfcaa597ddbb4eb580817df..eb0337c49546b6e976589a8719d996d8acd17a5c 100644 (file)
@@ -1,5 +1,6 @@
 config ATH_COMMON
        tristate "Atheros Wireless Cards"
+       depends on WLAN_80211
        depends on ATH5K || ATH9K || AR9170_USB
 
 source "drivers/net/wireless/ath/ath5k/Kconfig"
index ea045151f95325202b2674159afbcef12eb0ca9b..029c1bc7468ff17edfa5ba95e63ddb395e820643 100644 (file)
@@ -2970,6 +2970,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (modparam_nohwcrypt)
                return -EOPNOTSUPP;
 
+       if (sc->opmode == NL80211_IFTYPE_AP)
+               return -EOPNOTSUPP;
+
        switch (key->alg) {
        case ALG_WEP:
        case ALG_TKIP:
index 1aeafb511ddd8715207a74b5fece0a4d32cfb13e..aad259b4c1979c01f698a8354bb6c6d8374fb2c0 100644 (file)
@@ -478,6 +478,18 @@ void ath9k_ani_reset(struct ath_hw *ah)
                        "Reset ANI state opmode %u\n", ah->opmode);
                ah->stats.ast_ani_reset++;
 
+               if (ah->opmode == NL80211_IFTYPE_AP) {
+                       /*
+                        * ath9k_hw_ani_control() will only process items set on
+                        * ah->ani_function
+                        */
+                       if (IS_CHAN_2GHZ(chan))
+                               ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+                                                   ATH9K_ANI_FIRSTEP_LEVEL);
+                       else
+                               ah->ani_function = 0;
+               }
+
                ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
                ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
                ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
index b61a071788a50f98347ddaa7f74b778791372c4c..4ccf48e396dfd1529f4114fec7ae9c2d8829efbf 100644 (file)
@@ -355,7 +355,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                }
 
                if (bf_next == NULL) {
-                       INIT_LIST_HEAD(&bf_head);
+                       /*
+                        * Make sure the last desc is reclaimed if it
+                        * not a holding desc.
+                        */
+                       if (!bf_last->bf_stale)
+                               list_move_tail(&bf->list, &bf_head);
+                       else
+                               INIT_LIST_HEAD(&bf_head);
                } else {
                        ASSERT(!list_empty(bf_q));
                        list_move_tail(&bf->list, &bf_head);
index eef370bd12117643562f4b80b03c6e55b92b79f9..bf3d25ba7be1ffe6c5fe6b65f08ac59326ca4caf 100644 (file)
@@ -474,6 +474,21 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
        return 0;
 }
 
+/*
+ * Some users have reported their EEPROM programmed with
+ * 0x8000 set, this is not a supported regulatory domain
+ * but since we have more than one user with it we need
+ * a solution for them. We default to 0x64, which is the
+ * default Atheros world regulatory domain.
+ */
+static void ath_regd_sanitize(struct ath_regulatory *reg)
+{
+       if (reg->current_rd != COUNTRY_ERD_FLAG)
+               return;
+       printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n");
+       reg->current_rd = 0x64;
+}
+
 int
 ath_regd_init(struct ath_regulatory *reg,
              struct wiphy *wiphy,
@@ -486,6 +501,8 @@ ath_regd_init(struct ath_regulatory *reg,
        if (!reg)
                return -EINVAL;
 
+       ath_regd_sanitize(reg);
+
        printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
 
        if (!ath_regd_is_eeprom_valid(reg)) {
index f580c2812d91846d611c552295e9722fe09aa06f..40448067e4ccaff3276420d462ca4a8b232dca13 100644 (file)
@@ -648,6 +648,7 @@ struct b43_wl {
        u8 nr_devs;
 
        bool radiotap_enabled;
+       bool radio_enabled;
 
        /* The beacon we are currently using (AP or IBSS mode).
         * This beacon stuff is protected by the irq_lock. */
index 6456afebdba10d3268d6184a76695f253bce135b..e71c8d9cd706ee6b8340d295b86a20817f577d07 100644 (file)
@@ -3497,8 +3497,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        if (phy->ops->set_rx_antenna)
                phy->ops->set_rx_antenna(dev, antenna);
 
-       if (!!conf->radio_enabled != phy->radio_on) {
-               if (conf->radio_enabled) {
+       if (wl->radio_enabled != phy->radio_on) {
+               if (wl->radio_enabled) {
                        b43_software_rfkill(dev, false);
                        b43info(dev->wl, "Radio turned on by software\n");
                        if (!dev->radio_hw_enable) {
@@ -4339,6 +4339,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
        wl->beacon0_uploaded = 0;
        wl->beacon1_uploaded = 0;
        wl->beacon_templates_virgin = 1;
+       wl->radio_enabled = 1;
 
        mutex_lock(&wl->mutex);
 
@@ -4378,6 +4379,7 @@ static void b43_op_stop(struct ieee80211_hw *hw)
        if (b43_status(dev) >= B43_STAT_STARTED)
                b43_wireless_core_stop(dev);
        b43_wireless_core_exit(dev);
+       wl->radio_enabled = 0;
        mutex_unlock(&wl->mutex);
 
        cancel_work_sync(&(wl->txpower_adjust_work));
@@ -4560,6 +4562,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                B43_WARN_ON(1);
 
        dev->phy.gmode = have_2ghz_phy;
+       dev->phy.radio_on = 1;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
index 3cfc30307a27d33f48ed8bbffc3e2da13a2cc686..6c3a74964ab888585e0466424290415fcdf653e0 100644 (file)
@@ -35,6 +35,7 @@
 
 static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+       PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
        PCMCIA_DEVICE_NULL,
 };
 
index 77fda148ac4684b904e996095b1e7c68d3fa9469..038baa8869e233e038ca97b2919d0954f485d5ec 100644 (file)
@@ -607,6 +607,7 @@ struct b43legacy_wl {
        u8 nr_devs;
 
        bool radiotap_enabled;
+       bool radio_enabled;
 
        /* The beacon we are currently using (AP or IBSS mode).
         * This beacon stuff is protected by the irq_lock. */
index e5136fb65dddb066f3d6ab65b0671bf8386c3b97..c4973c1942bfdda4b5878b46e5120cc12d8c71bc 100644 (file)
@@ -2689,8 +2689,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
        /* Antennas for RX and management frame TX. */
        b43legacy_mgmtframe_txantenna(dev, antenna_tx);
 
-       if (!!conf->radio_enabled != phy->radio_on) {
-               if (conf->radio_enabled) {
+       if (wl->radio_enabled != phy->radio_on) {
+               if (wl->radio_enabled) {
                        b43legacy_radio_turn_on(dev);
                        b43legacyinfo(dev->wl, "Radio turned on by software\n");
                        if (!dev->radio_hw_enable)
@@ -3441,6 +3441,7 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
        wl->beacon0_uploaded = 0;
        wl->beacon1_uploaded = 0;
        wl->beacon_templates_virgin = 1;
+       wl->radio_enabled = 1;
 
        mutex_lock(&wl->mutex);
 
@@ -3479,6 +3480,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
        if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
                b43legacy_wireless_core_stop(dev);
        b43legacy_wireless_core_exit(dev);
+       wl->radio_enabled = 0;
        mutex_unlock(&wl->mutex);
 }
 
@@ -3620,6 +3622,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
                have_bphy = 1;
 
        dev->phy.gmode = (have_gphy || have_bphy);
+       dev->phy.radio_on = 1;
        tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
        b43legacy_wireless_core_reset(dev, tmp);
 
index 6d1519e1f011ad9f565a9256b3a6175dc54bb424..355f50ea7fef26ae07e42851e12c0203e26a3464 100644 (file)
@@ -2675,12 +2675,10 @@ static ssize_t show_power_level(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
-       int mode = priv->power_data.user_power_setting;
        int level = priv->power_data.power_mode;
        char *p = buf;
 
-       p += sprintf(p, "INDEX:%d\t", level);
-       p += sprintf(p, "USER:%d\n", mode);
+       p += sprintf(p, "%d\n", level);
        return p - buf + 1;
 }
 
index 85ae7a62109cd29475ce2b89e68468b05d25c484..9bbeec9427f0611b1f31725a0ea3b2578da4c8d1 100644 (file)
@@ -872,7 +872,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
 
        /* Set up entry for this TFD in Tx byte-count array */
-       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
+       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
                                                     le16_to_cpu(tx_cmd->len));
 
        pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
index cb9bd4c8f25e3bdbb24d4f8cbc10164515fa5cb1..956798f2c80c1eedb6f18c3681c036ddffd7b6d7 100644 (file)
@@ -3643,12 +3643,10 @@ static ssize_t show_power_level(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
-       int mode = priv->power_data.user_power_setting;
        int level = priv->power_data.power_mode;
        char *p = buf;
 
-       p += sprintf(p, "INDEX:%d\t", level);
-       p += sprintf(p, "USER:%d\n", mode);
+       p += sprintf(p, "%d\n", level);
        return p - buf + 1;
 }
 
index 1eccb6df46dd948664d75470172532b60211e6d4..030401d367d30aa7b82a894464fc2d973556fcef 100644 (file)
@@ -4,6 +4,15 @@ config IWM
        depends on CFG80211
        select WIRELESS_EXT
        select FW_LOADER
+       help
+         The Intel Wireless Multicomm 3200 hardware is a combo
+         card with GPS, Bluetooth, WiMax and 802.11 radios. It
+         runs over SDIO and is typically found on Moorestown
+         based platform. This driver takes care of the 802.11
+         part, which is a fullmac one.
+
+         If you choose to build it as a module, it'll be called
+         iwmc3200wifi.ko.
 
 config IWM_DEBUG
        bool "Enable full debugging output in iwmc3200wifi"
index aaa20c6885c8774c4e2af9e30164034456fb16f4..aea5ccf24ccf573533a48a22345aa5c464030010 100644 (file)
@@ -151,8 +151,8 @@ void iwm_if_free(struct iwm_priv *iwm)
                return;
 
        free_netdev(iwm_to_ndev(iwm));
-       iwm_wdev_free(iwm);
        iwm_priv_deinit(iwm);
+       iwm_wdev_free(iwm);
 }
 
 int iwm_if_add(struct iwm_priv *iwm)
index 01db705a38ec6da97629512949cec0b584c11b64..685098148e10e137a2cf14d47d491fc7a4973975 100644 (file)
@@ -135,8 +135,14 @@ int lbs_update_hw_spec(struct lbs_private *priv)
        /* Clamp region code to 8-bit since FW spec indicates that it should
         * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
         * returns non-zero high 8 bits here.
+        *
+        * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
+        * need to check for this problem and handle it properly.
         */
-       priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
+               priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
+       else
+               priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
 
        for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
                /* use the region code to search for the index */
index 48da157d6cdab3141ad95c3a2ae842ae3c2cae74..72f3479a4d702ff8f1ec90955f2e6a0dc14cee26 100644 (file)
@@ -234,6 +234,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 /** Mesh enable bit in FW capability */
 #define MESH_CAPINFO_ENABLE_MASK                       (1<<16)
 
+/** FW definition from Marvell v4 */
+#define MRVL_FW_V4                                     (0x04)
 /** FW definition from Marvell v5 */
 #define MRVL_FW_V5                                     (0x05)
 /** FW definition from Marvell v10 */
index e789c6e9938cb60e62a918b2f5e2083af7251591..7916ca3f84c8892420bcca591c9c3c122386a213 100644 (file)
@@ -418,6 +418,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                        continue;
 
                if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
+                   !data->channel || !data2->channel ||
                    data->channel->center_freq != data2->channel->center_freq ||
                    !(data->group & data2->group))
                        continue;
@@ -708,7 +709,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
 static void mac80211_hwsim_free(void)
 {
        struct list_head tmplist, *i, *tmp;
-       struct mac80211_hwsim_data *data;
+       struct mac80211_hwsim_data *data, *tmpdata;
 
        INIT_LIST_HEAD(&tmplist);
 
@@ -717,7 +718,7 @@ static void mac80211_hwsim_free(void)
                list_move(i, &tmplist);
        spin_unlock_bh(&hwsim_radio_lock);
 
-       list_for_each_entry(data, &tmplist, list) {
+       list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
                debugfs_remove(data->debugfs_group);
                debugfs_remove(data->debugfs_ps);
                debugfs_remove(data->debugfs);
@@ -1166,8 +1167,8 @@ static void __exit exit_mac80211_hwsim(void)
 {
        printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
 
-       unregister_netdev(hwsim_mon);
        mac80211_hwsim_free();
+       unregister_netdev(hwsim_mon);
 }
 
 
index 345593c4accbe3c2f007acd9836e66a9ff8375e0..a370e510f19f8e3800f8f30d55eda1587032bbf6 100644 (file)
@@ -2521,6 +2521,8 @@ static const struct net_device_ops orinoco_netdev_ops = {
        .ndo_start_xmit         = orinoco_xmit,
        .ndo_set_multicast_list = orinoco_set_multicast_list,
        .ndo_change_mtu         = orinoco_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = orinoco_tx_timeout,
        .ndo_get_stats          = orinoco_get_stats,
 };
@@ -2555,7 +2557,6 @@ struct net_device
        priv->wireless_data.spy_data = &priv->spy_data;
        dev->wireless_data = &priv->wireless_data;
 #endif
-       /* we use the default eth_mac_addr for setting the MAC addr */
 
        /* Reserve space in skb for the SNAP header */
        dev->hard_header_len += ENCAPS_OVERHEAD;
index 48d81d98e12d4993e15676dddd18863a99cbc09c..22ca122bd798c7d37ae3a7da4476b64dbacde233 100644 (file)
@@ -912,13 +912,14 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                }
 
                __skb_unlink(entry, &priv->tx_queue);
-               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
                frame_len = entry->len;
                entry_hdr = (struct p54_hdr *) entry->data;
                entry_data = (struct p54_tx_data *) entry_hdr->data;
-               priv->tx_stats[entry_data->hw_queue].len--;
+               if (priv->tx_stats[entry_data->hw_queue].len)
+                       priv->tx_stats[entry_data->hw_queue].len--;
                priv->stats.dot11ACKFailureCount += payload->tries - 1;
+               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
                /*
                 * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
index 83116baeb110082b2f94e3bb40186f8e98f97ad8..72c7dbd39d0ad48cfa1309229931bc69b33824ef 100644 (file)
@@ -635,7 +635,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)
 
        hw = p54_init_common(sizeof(*priv));
        if (!hw) {
-               dev_err(&priv->spi->dev, "could not alloc ieee80211_hw");
+               dev_err(&spi->dev, "could not alloc ieee80211_hw");
                return -ENOMEM;
        }
 
index 66daf68ff0ee9e35de4d0933413198432381cfbf..ce75426764a1538124eec73f20c3cac2859c06e0 100644 (file)
@@ -1550,7 +1550,9 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
        rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
 
-       if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0)) {
+       if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
+           rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+
                ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
                return -ENODEV;
        }
index b4425359224348c59f15fdb6a9a3031bc232406d..cf9f899fe0e65dc876637db60d87e1e6013a49e7 100644 (file)
@@ -208,11 +208,12 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
 
-       rtl8187_unregister_led(&priv->led_tx);
        /* turn the LED off before exiting */
        queue_delayed_work(dev->workqueue, &priv->led_off, 0);
        cancel_delayed_work_sync(&priv->led_off);
+       cancel_delayed_work_sync(&priv->led_on);
        rtl8187_unregister_led(&priv->led_rx);
+       rtl8187_unregister_led(&priv->led_tx);
 }
 #endif /* def CONFIG_RTL8187_LED */
 
index 14a19baff2144c512a9e28bb34c94584af9c1b06..0e6e44689cc61f863b9a25f936ab19d4ec943e6d 100644 (file)
@@ -38,7 +38,6 @@ static struct usb_device_id usb_ids[] = {
        /* ZD1211 */
        { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
@@ -61,6 +60,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
+       { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -87,6 +87,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
index aee967d7f760cec514a65d0d0853062b50bca0a2..bacaa536fd515aef951f8f0e8b4d1e4625d839ab 100644 (file)
@@ -9,6 +9,10 @@
  * out of the OpenFirmware device tree and using it to populate an mii_bus.
  */
 
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/err.h>
 #include <linux/phy.h>
 #include <linux/of.h>
 #include <linux/of_mdio.h>
@@ -137,3 +141,41 @@ struct phy_device *of_phy_connect(struct net_device *dev,
        return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect);
+
+/**
+ * of_phy_connect_fixed_link - Parse fixed-link property and return a dummy phy
+ * @dev: pointer to net_device claiming the phy
+ * @hndlr: Link state callback for the network device
+ * @iface: PHY data interface type
+ *
+ * This function is a temporary stop-gap and will be removed soon.  It is
+ * only to support the fs_enet, ucc_geth and gianfar Ethernet drivers.  Do
+ * not call this function from new drivers.
+ */
+struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
+                                            void (*hndlr)(struct net_device *),
+                                            phy_interface_t iface)
+{
+       struct device_node *net_np;
+       char bus_id[MII_BUS_ID_SIZE + 3];
+       struct phy_device *phy;
+       const u32 *phy_id;
+       int sz;
+
+       if (!dev->dev.parent)
+               return NULL;
+
+       net_np = dev_archdata_get_node(&dev->dev.parent->archdata);
+       if (!net_np)
+               return NULL;
+
+       phy_id = of_get_property(net_np, "fixed-link", &sz);
+       if (!phy_id || sz < sizeof(*phy_id))
+               return NULL;
+
+       sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]);
+
+       phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+       return IS_ERR(phy) ? NULL : phy;
+}
+EXPORT_SYMBOL(of_phy_connect_fixed_link);
index e1f6ce03705ed915d94b77f1dde0a687e07e08f8..3c2270a8300c40833bcf0900968635e2b166abc6 100644 (file)
@@ -33,6 +33,7 @@ void oprofile_reset_stats(void)
        atomic_set(&oprofile_stats.sample_lost_no_mm, 0);
        atomic_set(&oprofile_stats.sample_lost_no_mapping, 0);
        atomic_set(&oprofile_stats.event_lost_overflow, 0);
+       atomic_set(&oprofile_stats.bt_lost_no_mapping, 0);
 }
 
 
index a5b9f6ae507bb5cf23ab4cf614e97c1fa7e2c6d3..d703e73fffa7cc5cf334dbd003c7334a9bec42b1 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/pci_hotplug.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <asm/atomic.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
index 2fa47af992a8281ff1bfb43d5fd0e7c0c7bf2111..0ff689afa757bb1aa21df038623c4a63c41364f7 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/kthread.h>
index 8450f4a6568a852a288b75a62436e913b71e7ef8..e6089bdb6e5bddbc2b08e09c9419d26056e543e7 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/workqueue.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/smp_lock.h>
 #include <linux/debugfs.h>
 #include "cpqphp.h"
 
index ff4034502d240355b9e5dfd4c02b226606ba2f52..8aab8edf123eeecfc5d0bc5d79ae63a1685e6c0e 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/workqueue.h>
 #include "../pci.h"
index ec22284eed307ccf565eb83df55f960876f57cd4..e1c1ec5408934204c35025122cd5b64d6a14080e 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/errno.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <asm/uaccess.h>
 #include "pci.h"
index be2fd6f916390af3b0de060b5726bc7cec676974..fb45f5ee8df12a79c49e68ca88736f31920e5d80 100644 (file)
@@ -973,7 +973,7 @@ static int acer_rfkill_set(void *data, bool blocked)
 {
        acpi_status status;
        u32 cap = (unsigned long)data;
-       status = set_u32(!!blocked, cap);
+       status = set_u32(!blocked, cap);
        if (ACPI_FAILURE(status))
                return -ENODEV;
        return 0;
index 4ac2311c00afe9fae55fcf1334522a564fd943e5..ca508564a18144a519ee84c3d88c549b7b5d8ae7 100644 (file)
@@ -171,7 +171,7 @@ static int hp_wmi_tablet_state(void)
 static int hp_wmi_set_block(void *data, bool blocked)
 {
        unsigned long b = (unsigned long) data;
-       int query = BIT(b + 8) | ((!!blocked) << b);
+       int query = BIT(b + 8) | ((!blocked) << b);
 
        return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
 }
index 8bde92126d34794e6cd58e55f1d715216c92819b..b787335a8419352fa4cef23af9fccd2fd4f508ac 100644 (file)
@@ -33,14 +33,14 @@ static enum power_supply_property *prop;
 
 static unsigned long wm97xx_read_bat(struct power_supply *bat_ps)
 {
-       return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+       return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent),
                                        pdata->batt_aux) * pdata->batt_mult /
                                        pdata->batt_div;
 }
 
 static unsigned long wm97xx_read_temp(struct power_supply *bat_ps)
 {
-       return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
+       return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent),
                                        pdata->temp_aux) * pdata->temp_mult /
                                        pdata->temp_div;
 }
index f8b1f04f26b8ec248c0b69260f9e79d0a44ee8ec..c11770f5b368fe21dabef1ea826a280207176187 100644 (file)
@@ -1696,8 +1696,7 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
                DBF_DEV_EVENT(DBF_ERR, device, "%s",
                            "unsolicited interrupt received "
                            "(sense available)");
-               device->discipline->dump_sense_dbf(device, NULL, irb,
-                                                  "unsolicited");
+               device->discipline->dump_sense_dbf(device, irb, "unsolicited");
        }
 
        dasd_schedule_device_bh(device);
@@ -2941,42 +2940,20 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 }
 
 static void
-dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req,
-                        struct irb *irb, char *reason)
+dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
+                        char *reason)
 {
        u64 *sense;
-       int sl;
-       struct tsb *tsb;
 
-       sense = NULL;
-       tsb = NULL;
-       if (req && scsw_is_tm(&req->irb.scsw)) {
-               if (irb->scsw.tm.tcw)
-                       tsb = tcw_get_tsb(
-                               (struct tcw *)(unsigned long)irb->scsw.tm.tcw);
-               if (tsb && (irb->scsw.tm.fcxs == 0x01)) {
-                       switch (tsb->flags & 0x07) {
-                       case 1: /* tsa_iostat */
-                               sense = (u64 *)tsb->tsa.iostat.sense;
-                       break;
-                       case 2: /* ts_ddpc */
-                               sense = (u64 *)tsb->tsa.ddpc.sense;
-                       break;
-                       case 3: /* tsa_intrg */
-                       break;
-                       }
-               }
-       } else {
-               if (irb->esw.esw0.erw.cons)
-                       sense = (u64 *)irb->ecw;
-       }
+       sense = (u64 *) dasd_get_sense(irb);
        if (sense) {
-               for (sl = 0; sl < 4; sl++) {
-                       DBF_DEV_EVENT(DBF_EMERG, device,
-                                     "%s: %016llx %016llx %016llx %016llx",
-                                     reason, sense[0], sense[1], sense[2],
-                                     sense[3]);
-               }
+               DBF_DEV_EVENT(DBF_EMERG, device,
+                             "%s: %s %02x%02x%02x %016llx %016llx %016llx "
+                             "%016llx", reason,
+                             scsw_is_tm(&irb->scsw) ? "t" : "c",
+                             scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
+                             scsw_dstat(&irb->scsw), sense[0], sense[1],
+                             sense[2], sense[3]);
        } else {
                DBF_DEV_EVENT(DBF_EMERG, device, "%s",
                              "SORRY - NO VALID SENSE AVAILABLE\n");
index d970ce2814bedf9af63b5a74e1eb8ff967641820..cb8f9cef742903bc25d6a2402e90d82506c2e446 100644 (file)
@@ -172,7 +172,7 @@ dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb)
        device = cqr->startdev;
        /* dump sense data to s390 debugfeature*/
        if (device->discipline && device->discipline->dump_sense_dbf)
-               device->discipline->dump_sense_dbf(device, cqr, irb, "log");
+               device->discipline->dump_sense_dbf(device, irb, "log");
 }
 EXPORT_SYMBOL(dasd_log_sense_dbf);
 
index e21ee735f92673c4df91fb91a4c788f0b1d97b46..31849ad5e59fe6ddb84dbbb2ce2692165565b2a8 100644 (file)
@@ -241,7 +241,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
        /* check for unsolicited interrupts */
        DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                    "unsolicited interrupt received");
-       device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited");
+       device->discipline->dump_sense_dbf(device, irb, "unsolicited");
        dasd_schedule_device_bh(device);
        return;
 };
@@ -444,17 +444,20 @@ dasd_fba_fill_info(struct dasd_device * device,
 }
 
 static void
-dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req,
-                        struct irb *irb, char *reason)
+dasd_fba_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
+                       char *reason)
 {
-       int sl;
-       if (irb->esw.esw0.erw.cons) {
-               for (sl = 0; sl < 4; sl++) {
-                       DBF_DEV_EVENT(DBF_EMERG, device,
-                                     "%s: %08x %08x %08x %08x",
-                                     reason, irb->ecw[8 * 0], irb->ecw[8 * 1],
-                                     irb->ecw[8 * 2], irb->ecw[8 * 3]);
-               }
+       u64 *sense;
+
+       sense = (u64 *) dasd_get_sense(irb);
+       if (sense) {
+               DBF_DEV_EVENT(DBF_EMERG, device,
+                             "%s: %s %02x%02x%02x %016llx %016llx %016llx "
+                             "%016llx", reason,
+                             scsw_is_tm(&irb->scsw) ? "t" : "c",
+                             scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
+                             scsw_dstat(&irb->scsw), sense[0], sense[1],
+                             sense[2], sense[3]);
        } else {
                DBF_DEV_EVENT(DBF_EMERG, device, "%s",
                              "SORRY - NO VALID SENSE AVAILABLE\n");
index fd63b2f2bda9baeaefb4e0edefb2bd2407c4c913..b699ca356ac55077d287591e31225eb0a6fdea58 100644 (file)
@@ -284,8 +284,7 @@ struct dasd_discipline {
        dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
        void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
                            struct irb *);
-       void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *,
-                           struct irb *, char *);
+       void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *);
 
        void (*handle_unsolicited_interrupt) (struct dasd_device *,
                                              struct irb *);
index 4ce3f72ee1c13e2485e9a781b389f0eda2fd1c08..df918ef27965ccb6513e32635af8bb41bba561e0 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/blkpg.h>
+#include <linux/smp_lock.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cmb.h>
index 016f9e9d259186e14351168b682b168fb25ab58b..d34617682a6295172a2c0d5d5fa47e258e4d2b23 100644 (file)
@@ -964,7 +964,8 @@ static int dcssblk_freeze(struct device *dev)
                        break;
        }
        if (rc)
-               pr_err("Suspend failed because device %s is writeable.\n",
+               pr_err("Suspending the system failed because DCSS device %s "
+                      "is writable\n",
                       dev_info->segment_name);
        return rc;
 }
@@ -987,8 +988,8 @@ static int dcssblk_restore(struct device *dev)
                                goto out_panic;
                        }
                        if (start != entry->start || end != entry->end) {
-                               pr_err("Mismatch of start / end address after "
-                                      "resuming device %s\n",
+                               pr_err("The address range of DCSS %s changed "
+                                      "while the system was suspended\n",
                                       entry->segment_name);
                                goto out_panic;
                        }
index 2e9e1ecd6d82b2d1f03181d4237d04ff37dedab6..db442cd6621ec9d838325c15c2f47cbb102992a1 100644 (file)
@@ -443,7 +443,7 @@ fail:
  */
 static void xpram_resume_error(const char *message)
 {
-       pr_err("Resume error: %s\n", message);
+       pr_err("Resuming the system failed: %s\n", message);
        panic("xpram resume error\n");
 }
 
index 7892550d793280298175061811a59f2bb07b9256..3234e90bd7f99b6bc632c9844e53e4e479f0aae2 100644 (file)
@@ -320,7 +320,7 @@ static int mon_open(struct inode *inode, struct file *filp)
                goto out_path;
        }
        filp->private_data = monpriv;
-       dev_set_drvdata(&monreader_device, monpriv);
+       dev_set_drvdata(monreader_device, monpriv);
        unlock_kernel();
        return nonseekable_open(inode, filp);
 
@@ -463,7 +463,7 @@ static struct miscdevice mon_dev = {
  *****************************************************************************/
 static int monreader_freeze(struct device *dev)
 {
-       struct mon_private *monpriv = dev_get_drvdata(&dev);
+       struct mon_private *monpriv = dev_get_drvdata(dev);
        int rc;
 
        if (!monpriv)
index 85f491ea929c0da0df28ee54676949354f51b7b0..7a7bfc947d97eb3b502ccb39ee4fd21f751bdb5e 100644 (file)
@@ -92,5 +92,10 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short);
 void sclp_set_htab(struct sclp_buffer *, unsigned short);
 int sclp_chars_in_buffer(struct sclp_buffer *);
 
+#ifdef CONFIG_SCLP_CONSOLE
 void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
+#else
+static inline void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) { }
+#endif
+
 #endif /* __SCLP_RW_H__ */
index cb7854c10c0479585d1879f9c0a3fe8a90a713a1..f2bc287b69e4e4c1c5c35f01ddb500d2ca63aed9 100644 (file)
@@ -250,14 +250,14 @@ static int vmwdt_resume(void)
 static int vmwdt_suspend(void)
 {
        if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
-               pr_err("The watchdog is in use. "
-                       "This prevents hibernation or suspend.\n");
+               pr_err("The system cannot be suspended while the watchdog"
+                       " is in use\n");
                return NOTIFY_BAD;
        }
        if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) {
                clear_bit(VMWDT_OPEN, &vmwdt_is_open);
-               pr_err("The watchdog is running. "
-                       "This prevents hibernation or suspend.\n");
+               pr_err("The system cannot be suspended while the watchdog"
+                       " is running\n");
                return NOTIFY_BAD;
        }
        return NOTIFY_DONE;
index 727a809636d8a63ce93b1271175c3f520ac4455b..ed3dcdea7fe10cb7b521f7ccdb78a1bb5bfc86cc 100644 (file)
@@ -1145,12 +1145,17 @@ ap_config_timeout(unsigned long ptr)
  */
 static inline void ap_schedule_poll_timer(void)
 {
+       ktime_t hr_time;
        if (ap_using_interrupts() || ap_suspend_flag)
                return;
        if (hrtimer_is_queued(&ap_poll_timer))
                return;
-       hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout),
-                     HRTIMER_MODE_ABS);
+       if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
+               hr_time = ktime_set(0, poll_timeout);
+               hrtimer_forward_now(&ap_poll_timer, hr_time);
+               hrtimer_restart(&ap_poll_timer);
+       }
+       return;
 }
 
 /**
index 650bcef08f2a4d080f5e325a7fd82766179aeb7b..cd78c501803a733759f768e049860f6acdd68f21 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
 #include <linux/list.h>
 
 #include <scsi/scsi_tcq.h>
index 4d6f2fe1cfe9987ee5a6be65dfc75fc77111745e..9230402c45afcbe0c1a06188b83c99a3f39a104b 100644 (file)
@@ -1656,6 +1656,10 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
                md->nr_entries = req_schp->k_use_sg;
                md->offset = 0;
                md->null_mapped = hp->dxferp ? 0 : 1;
+               if (dxfer_dir == SG_DXFER_TO_FROM_DEV)
+                       md->from_user = 1;
+               else
+                       md->from_user = 0;
        }
 
        if (iov_count) {
index 34b4ae0fe76041f4eda4132e1a81a54784652557..c108b1a0ce988de4fd91d905d7b26fc205c00e7d 100644 (file)
@@ -236,7 +236,6 @@ static int sport_startup(struct uart_port *port)
        int retval;
 
        pr_debug("%s enter\n", __func__);
-       memset(buffer, 20, '\0');
        snprintf(buffer, 20, "%s rx", up->name);
        retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
        if (retval) {
index 698048f64f5e9aa0ef49d51578460978815b1dc6..f7c24baa141673a03084e3951b80d345c205d3c6 100644 (file)
@@ -730,7 +730,6 @@ static int __devexit msm_serial_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver msm_platform_driver = {
-       .probe = msm_serial_probe,
        .remove = msm_serial_remove,
        .driver = {
                .name = "msm_serial",
index 131030f693c76913683c95f1bf81c646ff71b7aa..100e7a5c5ea1f3a48991845ba1e1cf06758e462c 100644 (file)
@@ -678,7 +678,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                        sprom->board_rev = tuple.TupleData[1];
                        break;
                case SSB_PCMCIA_CIS_PA:
-                       GOTO_ERROR_ON(tuple.TupleDataLen != 9,
+                       GOTO_ERROR_ON((tuple.TupleDataLen != 9) &&
+                                     (tuple.TupleDataLen != 10),
                                      "pa tpl size");
                        sprom->pa0b0 = tuple.TupleData[1] |
                                 ((u16)tuple.TupleData[2] << 8);
@@ -718,7 +719,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                        sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
                        break;
                case SSB_PCMCIA_CIS_BFLAGS:
-                       GOTO_ERROR_ON(tuple.TupleDataLen != 3,
+                       GOTO_ERROR_ON((tuple.TupleDataLen != 3) &&
+                                     (tuple.TupleDataLen != 5),
                                      "bfl tpl size");
                        sprom->boardflags_lo = tuple.TupleData[1] |
                                         ((u16)tuple.TupleData[2] << 8);
index 348bf61a8fec96a2f8daa0389ae6578d47a9c0dd..975ecddbce30b48a4b20ed5ac955a48d7f224405 100644 (file)
@@ -103,8 +103,6 @@ source "drivers/staging/pohmelfs/Kconfig"
 
 source "drivers/staging/stlc45xx/Kconfig"
 
-source "drivers/staging/uc2322/Kconfig"
-
 source "drivers/staging/b3dfg/Kconfig"
 
 source "drivers/staging/phison/Kconfig"
index 8d61d7b4debfb78c1279ceac0c4379ac10b6a94d..2241ae1b21ee1ad47927386c6c5e4e2af4f83f4f 100644 (file)
@@ -34,7 +34,6 @@ obj-$(CONFIG_ANDROID)         += android/
 obj-$(CONFIG_DST)              += dst/
 obj-$(CONFIG_POHMELFS)         += pohmelfs/
 obj-$(CONFIG_STLC45XX)         += stlc45xx/
-obj-$(CONFIG_USB_SERIAL_ATEN2011)      += uc2322/
 obj-$(CONFIG_B3DFG)            += b3dfg/
 obj-$(CONFIG_IDE_PHISON)       += phison/
 obj-$(CONFIG_PLAN9AUTH)                += p9auth/
index fe72240f5a9e3bf9af573286cbce6810950db00e..f934393f39597c7ee1fc2baebf503b90222d636c 100644 (file)
@@ -96,19 +96,21 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
 
        read_lock(&tasklist_lock);
        for_each_process(p) {
+               struct mm_struct *mm;
                int oom_adj;
 
                task_lock(p);
-               if (!p->mm) {
+               mm = p->mm;
+               if (!mm) {
                        task_unlock(p);
                        continue;
                }
-               oom_adj = p->oomkilladj;
+               oom_adj = mm->oom_adj;
                if (oom_adj < min_adj) {
                        task_unlock(p);
                        continue;
                }
-               tasksize = get_mm_rss(p->mm);
+               tasksize = get_mm_rss(mm);
                task_unlock(p);
                if (tasksize <= 0)
                        continue;
index baf83c6a9412418be67392cb9dfc4a4425e26143..e3c3adc282e2592376a1fe5bca9b68a5d7e18096 100644 (file)
@@ -45,6 +45,8 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
 #include <linux/delay.h>
 #include <linux/ctype.h>
 #include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include "comedi_pci.h"
 #include "jr3_pci.h"
 
index 92121cf8c45cddb758a108febd5bd878c8757b92..5d9bab352c1d549806e36e1fca4520385ef8eb26 100644 (file)
@@ -111,9 +111,13 @@ static const struct s626_board s626_boards[] = {
 #define PCI_VENDOR_ID_S626 0x1131
 #define PCI_DEVICE_ID_S626 0x7146
 
+/*
+ * For devices with vendor:device id == 0x1131:0x7146 you must specify
+ * also subvendor:subdevice ids, because otherwise it will conflict with
+ * Philips SAA7146 media/dvb based cards.
+ */
 static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
-       {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               0},
+       {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0},
        {0}
 };
 
@@ -499,25 +503,26 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        resource_size_t resourceStart;
        dma_addr_t appdma;
        struct comedi_subdevice *s;
-       struct pci_dev *pdev;
+       const struct pci_device_id *ids;
+       struct pci_dev *pdev = NULL;
 
        if (alloc_private(dev, sizeof(struct s626_private)) < 0)
                return -ENOMEM;
 
-       for (pdev = pci_get_device(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
-                       NULL); pdev != NULL;
-               pdev = pci_get_device(PCI_VENDOR_ID_S626,
-                       PCI_DEVICE_ID_S626, pdev)) {
-               if (it->options[0] || it->options[1]) {
-                       if (pdev->bus->number == it->options[0] &&
-                               PCI_SLOT(pdev->devfn) == it->options[1]) {
+       for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) {
+               ids = &s626_pci_table[i];
+               do {
+                       pdev = pci_get_subsys(ids->vendor, ids->device, ids->subvendor,
+                                             ids->subdevice, pdev);
+
+                       if ((it->options[0] || it->options[1]) && pdev) {
                                /* matches requested bus/slot */
+                               if (pdev->bus->number == it->options[0] &&
+                                   PCI_SLOT(pdev->devfn) == it->options[1])
+                                       break;
+                       } else
                                break;
-                       }
-               } else {
-                       /* no bus/slot specified */
-                       break;
-               }
+               } while (1);
        }
        devpriv->pdev = pdev;
 
index a5e4acab089e034c5ddd1faba37df5313526c6d1..bb22347af60e8f2ecd852ed68ffb0ef9c95899ee 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <dvb-usb.h>
 
index 6ec25203089c84f7a467327b322e324d98fcee00..d6ce39823de673378daae4696e17dcbe63210761 100644 (file)
@@ -7,4 +7,4 @@ TODO:
        - possible comedi merge
 
 Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com>
-and CC: David Kiliani <mail@davidkiliani.de>
+and CC: David Kiliani <mail@davidkiliani.de> and Meilhaus Support <support@meilhaus.de>
index 1cdfe69585ea666d63b8e16175f2705c1529461b..2f8155c1968b31652f63f781c0e15071fd25afe6 100644 (file)
@@ -444,8 +444,7 @@ static void piusb_write_bulk_callback(struct urb *urb)
                        __func__, status);
 
        pdx->pendingWrite = 0;
-       usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-                       urb->transfer_buffer, urb->transfer_dma);
+       kfree(urb->transfer_buffer);
 }
 
 int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
@@ -457,9 +456,7 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
 
        urb = usb_alloc_urb(0, GFP_KERNEL);
        if (urb != NULL) {
-               kbuf =
-                   usb_buffer_alloc(pdx->udev, len, GFP_KERNEL,
-                                    &urb->transfer_dma);
+               kbuf = kmalloc(len, GFP_KERNEL);
                if (!kbuf) {
                        dev_err(&pdx->udev->dev, "buffer_alloc failed\n");
                        return -ENOMEM;
@@ -470,7 +467,6 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
                }
                usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf,
                                  len, piusb_write_bulk_callback, pdx);
-               urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                err = usb_submit_urb(urb, GFP_KERNEL);
                if (err) {
                        dev_err(&pdx->udev->dev,
@@ -641,7 +637,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
        numPagesRequired =
            ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
        dbg("Number of pages needed = %d", numPagesRequired);
-       maplist_p = vmalloc(numPagesRequired * sizeof(struct page));
+       maplist_p = vmalloc(numPagesRequired * sizeof(struct page *));
        if (!maplist_p) {
                dbg("Can't Allocate Memory for maplist_p");
                return -ENOMEM;
@@ -712,9 +708,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
                usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i],
                                  pdx->udev,
                                  epAddr,
-                                 (dma_addr_t *) sg_dma_address(&pdx->
-                                                               sgl[frameInfo]
-                                                               [i]),
+                                 NULL, // non-DMA HC? buy a better hardware
                                  sg_dma_len(&pdx->sgl[frameInfo][i]),
                                  piusb_readPIXEL_callback, (void *)pdx);
                pdx->PixelUrb[frameInfo][i]->transfer_dma =
index 5e5b3f2b7eb1e757975763c64409058ebf345015..29e3b53e52a1be04c06797344ed95ff810d23e40 100644 (file)
@@ -89,6 +89,7 @@
        {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */              \
        {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */              \
        {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom */              \
+       {USB_DEVICE(0x0DF6,0x003F)}, /* Sitecom WL-608 */       \
        {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */         \
        {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */         \
        {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */          \
index 93af37e2d31a0b453031ffff3c79f852f6d79022..54b4b718f84a5f09fa2cd3a491f423d781276bc7 100644 (file)
@@ -461,19 +461,19 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
 {
-       strcpy(wrqu->name, "802.11");
+       strlcpy(wrqu->name, "802.11", IFNAMSIZ);
        if(ieee->modulation & IEEE80211_CCK_MODULATION){
-               strcat(wrqu->name, "b");
+               strlcat(wrqu->name, "b", IFNAMSIZ);
                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-                       strcat(wrqu->name, "/g");
+                       strlcat(wrqu->name, "/g", IFNAMSIZ);
        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-               strcat(wrqu->name, "g");
+               strlcat(wrqu->name, "g", IFNAMSIZ);
 
        if((ieee->state == IEEE80211_LINKED) ||
                (ieee->state == IEEE80211_LINKED_SCANNING))
-               strcat(wrqu->name," linked");
+               strlcat(wrqu->name,"  link", IFNAMSIZ);
        else if(ieee->state != IEEE80211_NOLINK)
-               strcat(wrqu->name," link..");
+               strlcat(wrqu->name," .....", IFNAMSIZ);
 
 
        return 0;
index 4b5552c5926e33c79309c73610d70bb453f30be2..770f41280f21d5412a93761b2ea8522b88fce4f9 100644 (file)
@@ -1,6 +1,6 @@
 config RTL8192SU
        tristate "RealTek RTL8192SU Wireless LAN NIC driver"
        depends on PCI
-       depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS
+       depends on WIRELESS_EXT
        default N
        ---help---
index f408b4583b82981a1626a909e8505e76fc0e1349..759032db4a3482fd03fdfc2f3c1f49aa152c03ae 100644 (file)
@@ -118,7 +118,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
 #else
        ieee = (struct ieee80211_device *)dev->priv;
 #endif
-       dev->hard_start_xmit = ieee80211_xmit;
 
        memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
        ieee->dev = dev;
index 1f50c46dcb90636d765ebf879d0d39e61fe15473..191dc3fbbe32e09d1efbf3f3a66fee78c68703c8 100644 (file)
@@ -548,21 +548,21 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
 {
-       strcpy(wrqu->name, "802.11");
+       strlcpy(wrqu->name, "802.11", IFNAMSIZ);
        if(ieee->modulation & IEEE80211_CCK_MODULATION){
-               strcat(wrqu->name, "b");
+               strlcat(wrqu->name, "b", IFNAMSIZ);
                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-                       strcat(wrqu->name, "/g");
+                       strlcat(wrqu->name, "/g", IFNAMSIZ);
        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
-               strcat(wrqu->name, "g");
+               strlcat(wrqu->name, "g", IFNAMSIZ);
        if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
-               strcat(wrqu->name, "/n");
+               strlcat(wrqu->name, "/n", IFNAMSIZ);
 
        if((ieee->state == IEEE80211_LINKED) ||
                (ieee->state == IEEE80211_LINKED_SCANNING))
-               strcat(wrqu->name," linked");
+               strlcat(wrqu->name, "  link", IFNAMSIZ);
        else if(ieee->state != IEEE80211_NOLINK)
-               strcat(wrqu->name," link..");
+               strlcat(wrqu->name, " .....", IFNAMSIZ);
 
 
        return 0;
index f1423d714496ac97ce40b193cb2a573d4897ebf6..4ab250743e81984c0dbcf9282bffc23ee7248984 100644 (file)
@@ -12132,6 +12132,19 @@ static void HalUsbSetQueuePipeMapping8192SUsb(struct usb_interface *intf, struct
 }
 #endif
 
+static const struct net_device_ops rtl8192_netdev_ops = {
+       .ndo_open               = rtl8192_open,
+       .ndo_stop               = rtl8192_close,
+       .ndo_get_stats          = rtl8192_stats,
+       .ndo_tx_timeout         = tx_timeout,
+       .ndo_do_ioctl           = rtl8192_ioctl,
+       .ndo_set_multicast_list = r8192_set_multicast,
+       .ndo_set_mac_address    = r8192_set_mac_adr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_start_xmit         = ieee80211_xmit,
+};
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -12186,15 +12199,7 @@ static void * __devinit rtl8192_usb_probe(struct usb_device *udev,
        priv->ops = &rtl8192u_ops;
 #endif
 
-       dev->open = rtl8192_open;
-       dev->stop = rtl8192_close;
-       //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit;
-       dev->tx_timeout = tx_timeout;
-       //dev->wireless_handlers = &r8192_wx_handlers_def;
-       dev->do_ioctl = rtl8192_ioctl;
-       dev->set_multicast_list = r8192_set_multicast;
-       dev->set_mac_address = r8192_set_mac_adr;
-       dev->get_stats = rtl8192_stats;
+       dev->netdev_ops = &rtl8192_netdev_ops;
 
          //DMESG("Oops: i'm coming\n");
 #if WIRELESS_EXT >= 12
index 92c95aa36638077cea8b5328b4aafcda480c33bf..b1531a8d0cde12d0ee656d074ce45452fb834ac7 100644 (file)
@@ -35,7 +35,9 @@ int rtl8192U_suspend(struct usb_interface *intf, pm_message_t state)
                      return 0;
                 }
 
-               dev->stop(dev);
+               if (dev->netdev_ops->ndo_stop)
+                       dev->netdev_ops->ndo_stop(dev);
+
                mdelay(10);
 
                netif_device_detach(dev);
@@ -61,7 +63,9 @@ int rtl8192U_resume (struct usb_interface *intf)
                }
 
                netif_device_attach(dev);
-               dev->open(dev);
+
+               if (dev->netdev_ops->ndo_open)
+                       dev->netdev_ops->ndo_open(dev);
        }
 
         return 0;
index 90b29b564631656711694df46111dff8c4e8cda0..0fdf8c6dc648a69eaeeac311b1e24a3cb51d85e9 100644 (file)
@@ -360,18 +360,18 @@ static void qt_read_bulk_callback(struct urb *urb)
        if (port_paranoia_check(port, __func__) != 0) {
                dbg("%s - port_paranoia_check, exiting\n", __func__);
                qt_port->ReadBulkStopped = 1;
-               return;
+               goto exit;
        }
 
        if (!serial) {
                dbg("%s - bad serial pointer, exiting\n", __func__);
-               return;
+               goto exit;
        }
        if (qt_port->closePending == 1) {
                /* Were closing , stop reading */
                dbg("%s - (qt_port->closepending == 1\n", __func__);
                qt_port->ReadBulkStopped = 1;
-               return;
+               goto exit;
        }
 
        /*
@@ -381,7 +381,7 @@ static void qt_read_bulk_callback(struct urb *urb)
         */
        if (qt_port->RxHolding == 1) {
                qt_port->ReadBulkStopped = 1;
-               return;
+               goto exit;
        }
 
        if (urb->status) {
@@ -389,7 +389,7 @@ static void qt_read_bulk_callback(struct urb *urb)
 
                dbg("%s - nonzero read bulk status received: %d\n",
                    __func__, urb->status);
-               return;
+               goto exit;
        }
 
        if (tty && RxCount) {
@@ -463,6 +463,8 @@ static void qt_read_bulk_callback(struct urb *urb)
        }
 
        schedule_work(&port->work);
+exit:
+       tty_kref_put(tty);
 }
 
 /*
@@ -736,6 +738,11 @@ static int qt_startup(struct usb_serial *serial)
                if (!qt_port) {
                        dbg("%s: kmalloc for quatech_port (%d) failed!.",
                            __func__, i);
+                       for(--i; i >= 0; i--) {
+                               port = serial->port[i];
+                               kfree(usb_get_serial_port_data(port));
+                               usb_set_serial_port_data(port, NULL);
+                       }
                        return -ENOMEM;
                }
                spin_lock_init(&qt_port->lock);
@@ -866,7 +873,7 @@ static void qt_release(struct usb_serial *serial)
 
 }
 
-int qt_open(struct tty_struct *tty,
+static int qt_open(struct tty_struct *tty,
            struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial;
@@ -1041,17 +1048,19 @@ static void qt_block_until_empty(struct tty_struct *tty,
        }
 }
 
-static void qt_close(struct tty_struct *tty, struct usb_serial_port *port,
-                    struct file *filp)
+static void qt_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct quatech_port *qt_port;
        struct quatech_port *port0;
+       struct tty_struct *tty;
        int status;
        unsigned int index;
        status = 0;
 
        dbg("%s - port %d\n", __func__, port->number);
+
+       tty = tty_port_tty_get(&port->port);
        index = tty->index - serial->minor;
 
        qt_port = qt_get_port_private(port);
@@ -1066,6 +1075,7 @@ static void qt_close(struct tty_struct *tty, struct usb_serial_port *port,
        /* wait up to for transmitter to empty */
        if (serial->dev)
                qt_block_until_empty(tty, qt_port);
+       tty_kref_put(tty);
 
        /* Close uart channel */
        status = qt_close_channel(serial, index);
index cfdaac9b747edbc15cc3c0c0746772815b6ddd9c..a137c78fac0982ee293860344bc172b757fb7ead 100644 (file)
@@ -2235,24 +2235,6 @@ static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw,
        stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
 }
 
-static int stlc45xx_op_config_interface(struct ieee80211_hw *hw,
-                                       struct ieee80211_vif *vif,
-                                       struct ieee80211_if_conf *conf)
-{
-       struct stlc45xx *stlc = hw->priv;
-
-       stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
-
-       mutex_lock(&stlc->mutex);
-
-       memcpy(stlc->bssid, conf->bssid, ETH_ALEN);
-       stlc45xx_tx_setup(stlc);
-
-       mutex_unlock(&stlc->mutex);
-
-       return 0;
-}
-
 static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct stlc45xx *stlc = hw->priv;
@@ -2295,6 +2277,14 @@ static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct stlc45xx *stlc = hw->priv;
 
+       stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+       mutex_lock(&stlc->mutex);
+
+       memcpy(stlc->bssid, info->bssid, ETH_ALEN);
+       stlc45xx_tx_setup(stlc);
+
+       mutex_unlock(&stlc->mutex);
+
        if (changed & BSS_CHANGED_ASSOC) {
                stlc->associated = info->assoc;
                if (info->assoc)
@@ -2357,7 +2347,6 @@ static const struct ieee80211_ops stlc45xx_ops = {
        .add_interface = stlc45xx_op_add_interface,
        .remove_interface = stlc45xx_op_remove_interface,
        .config = stlc45xx_op_config,
-       .config_interface = stlc45xx_op_config_interface,
        .configure_filter = stlc45xx_op_configure_filter,
        .tx = stlc45xx_op_tx,
        .bss_info_changed = stlc45xx_op_bss_info_changed,
diff --git a/drivers/staging/uc2322/Kconfig b/drivers/staging/uc2322/Kconfig
deleted file mode 100644 (file)
index 2e0c6e7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config USB_SERIAL_ATEN2011
-       tristate "ATEN 2011 USB to serial device support"
-       depends on USB_SERIAL
-       default N
-       ---help---
-         Say Y here if you want to use a ATEN 2011 dual port USB to serial
-         adapter.
-
-         To compile this driver as a module, choose M here: the module will be
-         called aten2011.
diff --git a/drivers/staging/uc2322/Makefile b/drivers/staging/uc2322/Makefile
deleted file mode 100644 (file)
index 49c18d6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SERIAL_ATEN2011)      += aten2011.o
diff --git a/drivers/staging/uc2322/TODO b/drivers/staging/uc2322/TODO
deleted file mode 100644 (file)
index c189a64..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-TODO:
-       - checkpatch.pl cleanups
-       - remove dead and useless code (auditing the tty ioctls to
-         verify that they really are correct and needed.)
-
-Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-Russell Lang <gsview@ghostgum.com.au>.
diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c
deleted file mode 100644 (file)
index 39d0926..0000000
+++ /dev/null
@@ -1,2430 +0,0 @@
-/*
- * Aten 2011 USB serial driver for 4 port devices
- *
- * Copyright (C) 2000 Inside Out Networks
- * Copyright (C) 2001-2002, 2009 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2009 Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-
-#define ZLP_REG1               0x3A    /* Zero_Flag_Reg1 58 */
-#define ZLP_REG2               0x3B    /* Zero_Flag_Reg2 59 */
-#define ZLP_REG3               0x3C    /* Zero_Flag_Reg3 60 */
-#define ZLP_REG4               0x3D    /* Zero_Flag_Reg4 61 */
-#define ZLP_REG5               0x3E    /* Zero_Flag_Reg5 62 */
-
-/* Interrupt Rotinue Defines   */
-#define SERIAL_IIR_RLS         0x06
-#define SERIAL_IIR_RDA         0x04
-#define SERIAL_IIR_CTI         0x0c
-#define SERIAL_IIR_THR         0x02
-#define SERIAL_IIR_MS          0x00
-
-/* Emulation of the bit mask on the LINE STATUS REGISTER.  */
-#define SERIAL_LSR_DR          0x0001
-#define SERIAL_LSR_OE          0x0002
-#define SERIAL_LSR_PE          0x0004
-#define SERIAL_LSR_FE          0x0008
-#define SERIAL_LSR_BI          0x0010
-#define SERIAL_LSR_THRE                0x0020
-#define SERIAL_LSR_TEMT                0x0040
-#define SERIAL_LSR_FIFOERR     0x0080
-
-/* MSR bit defines(place holders) */
-#define ATEN_MSR_DELTA_CTS     0x10
-#define ATEN_MSR_DELTA_DSR     0x20
-#define ATEN_MSR_DELTA_RI      0x40
-#define ATEN_MSR_DELTA_CD      0x80
-
-/* Serial Port register Address */
-#define RECEIVE_BUFFER_REGISTER                ((__u16)(0x00))
-#define TRANSMIT_HOLDING_REGISTER      ((__u16)(0x00))
-#define INTERRUPT_ENABLE_REGISTER      ((__u16)(0x01))
-#define INTERRUPT_IDENT_REGISTER       ((__u16)(0x02))
-#define FIFO_CONTROL_REGISTER          ((__u16)(0x02))
-#define LINE_CONTROL_REGISTER          ((__u16)(0x03))
-#define MODEM_CONTROL_REGISTER         ((__u16)(0x04))
-#define LINE_STATUS_REGISTER           ((__u16)(0x05))
-#define MODEM_STATUS_REGISTER          ((__u16)(0x06))
-#define SCRATCH_PAD_REGISTER           ((__u16)(0x07))
-#define DIVISOR_LATCH_LSB              ((__u16)(0x00))
-#define DIVISOR_LATCH_MSB              ((__u16)(0x01))
-
-#define SP1_REGISTER                   ((__u16)(0x00))
-#define CONTROL1_REGISTER              ((__u16)(0x01))
-#define CLK_MULTI_REGISTER             ((__u16)(0x02))
-#define CLK_START_VALUE_REGISTER       ((__u16)(0x03))
-#define DCR1_REGISTER                  ((__u16)(0x04))
-#define GPIO_REGISTER                  ((__u16)(0x07))
-
-#define SERIAL_LCR_DLAB                        ((__u16)(0x0080))
-
-/*
- * URB POOL related defines
- */
-#define NUM_URBS                       16      /* URB Count */
-#define URB_TRANSFER_BUFFER_SIZE       32      /* URB Size  */
-
-#define USB_VENDOR_ID_ATENINTL         0x0557
-#define ATENINTL_DEVICE_ID_2011                0x2011
-#define ATENINTL_DEVICE_ID_7820                0x7820
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_2011) },
-       { USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_7820) },
-       { } /* terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-/* This structure holds all of the local port information */
-struct ATENINTL_port {
-       int             port_num;          /*Actual port number in the device(1,2,etc)*/
-       __u8            bulk_out_endpoint;      /* the bulk out endpoint handle */
-       unsigned char   *bulk_out_buffer;       /* buffer used for the bulk out endpoint */
-       struct urb      *write_urb;             /* write URB for this port */
-       __u8            bulk_in_endpoint;       /* the bulk in endpoint handle */
-       unsigned char   *bulk_in_buffer;        /* the buffer we use for the bulk in endpoint */
-       struct urb      *read_urb;              /* read URB for this port */
-       __u8            shadowLCR;              /* last LCR value received */
-       __u8            shadowMCR;              /* last MCR value received */
-       char            open;
-       char            chaseResponsePending;
-       wait_queue_head_t       wait_chase;             /* for handling sleeping while waiting for chase to finish */
-       wait_queue_head_t       wait_command;           /* for handling sleeping while waiting for command to finish */
-       struct async_icount     icount;
-       struct usb_serial_port  *port;                  /* loop back to the owner of this object */
-       /*Offsets*/
-       __u8            SpRegOffset;
-       __u8            ControlRegOffset;
-       __u8            DcrRegOffset;
-       /* for processing control URBS in interrupt context */
-       struct urb      *control_urb;
-       char            *ctrl_buf;
-       int             MsrLsr;
-
-       struct urb      *write_urb_pool[NUM_URBS];
-       /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
-       struct ktermios tmp_termios;        /* stores the old termios settings */
-       spinlock_t      lock;                   /* private lock */
-};
-
-/* This structure holds all of the individual serial device information */
-struct ATENINTL_serial {
-       __u8            interrupt_in_endpoint;          /* the interrupt endpoint handle */
-       unsigned char   *interrupt_in_buffer;           /* the buffer we use for the interrupt endpoint */
-       struct urb      *interrupt_read_urb;    /* our interrupt urb */
-       __u8            bulk_in_endpoint;       /* the bulk in endpoint handle */
-       unsigned char   *bulk_in_buffer;                /* the buffer we use for the bulk in endpoint */
-       struct urb      *read_urb;              /* our bulk read urb */
-       __u8            bulk_out_endpoint;      /* the bulk out endpoint handle */
-       struct usb_serial       *serial;        /* loop back to the owner of this object */
-       int     ATEN2011_spectrum_2or4ports;    /* this says the number of ports in the device */
-       /* Indicates about the no.of opened ports of an individual USB-serial adapater. */
-       unsigned int    NoOfOpenPorts;
-       /* a flag for Status endpoint polling */
-       unsigned char   status_polling_started;
-};
-
-static void ATEN2011_set_termios(struct tty_struct *tty,
-                                struct usb_serial_port *port,
-                                struct ktermios *old_termios);
-static void ATEN2011_change_port_settings(struct tty_struct *tty,
-                                         struct ATENINTL_port *ATEN2011_port,
-                                         struct ktermios *old_termios);
-
-/*************************************
- * Bit definitions for each register *
- *************************************/
-#define LCR_BITS_5             0x00    /* 5 bits/char */
-#define LCR_BITS_6             0x01    /* 6 bits/char */
-#define LCR_BITS_7             0x02    /* 7 bits/char */
-#define LCR_BITS_8             0x03    /* 8 bits/char */
-#define LCR_BITS_MASK          0x03    /* Mask for bits/char field */
-
-#define LCR_STOP_1             0x00    /* 1 stop bit */
-#define LCR_STOP_1_5           0x04    /* 1.5 stop bits (if 5   bits/char) */
-#define LCR_STOP_2             0x04    /* 2 stop bits   (if 6-8 bits/char) */
-#define LCR_STOP_MASK          0x04    /* Mask for stop bits field */
-
-#define LCR_PAR_NONE           0x00    /* No parity */
-#define LCR_PAR_ODD            0x08    /* Odd parity */
-#define LCR_PAR_EVEN           0x18    /* Even parity */
-#define LCR_PAR_MARK           0x28    /* Force parity bit to 1 */
-#define LCR_PAR_SPACE          0x38    /* Force parity bit to 0 */
-#define LCR_PAR_MASK           0x38    /* Mask for parity field */
-
-#define LCR_SET_BREAK          0x40    /* Set Break condition */
-#define LCR_DL_ENABLE          0x80    /* Enable access to divisor latch */
-
-#define MCR_DTR                        0x01    /* Assert DTR */
-#define MCR_RTS                        0x02    /* Assert RTS */
-#define MCR_OUT1               0x04    /* Loopback only: Sets state of RI */
-#define MCR_MASTER_IE          0x08    /* Enable interrupt outputs */
-#define MCR_LOOPBACK           0x10    /* Set internal (digital) loopback mode */
-#define MCR_XON_ANY            0x20    /* Enable any char to exit XOFF mode */
-
-#define ATEN2011_MSR_CTS       0x10    /* Current state of CTS */
-#define ATEN2011_MSR_DSR       0x20    /* Current state of DSR */
-#define ATEN2011_MSR_RI                0x40    /* Current state of RI */
-#define ATEN2011_MSR_CD                0x80    /* Current state of CD */
-
-
-static int debug;
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "2.0"
-#define DRIVER_DESC "ATENINTL 2011 USB Serial Adapter"
-
-/*
- * Defines used for sending commands to port
- */
-
-#define ATEN_WDR_TIMEOUT       (50)    /* default urb timeout */
-
-/* Requests */
-#define ATEN_RD_RTYPE          0xC0
-#define ATEN_WR_RTYPE          0x40
-#define ATEN_RDREQ             0x0D
-#define ATEN_WRREQ             0x0E
-#define ATEN_CTRL_TIMEOUT      500
-#define VENDOR_READ_LENGTH     (0x01)
-
-/* set to 1 for RS485 mode and 0 for RS232 mode */
-/* FIXME make this somehow dynamic and not build time specific */
-static int RS485mode;
-
-static int set_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 val)
-{
-       struct usb_device *dev = port->serial->dev;
-       val = val & 0x00ff;
-
-       dbg("%s: is %x, value %x", __func__, reg, val);
-
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
-                              ATEN_WR_RTYPE, val, reg, NULL, 0,
-                              ATEN_WDR_TIMEOUT);
-}
-
-static int get_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 *val)
-{
-       struct usb_device *dev = port->serial->dev;
-       int ret;
-
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
-                             ATEN_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
-                             ATEN_WDR_TIMEOUT);
-       dbg("%s: offset is %x, return val %x", __func__, reg, *val);
-       *val = (*val) & 0x00ff;
-       return ret;
-}
-
-static int set_uart_reg(struct usb_serial_port *port, __u16 reg, __u16 val)
-{
-       struct usb_device *dev = port->serial->dev;
-       struct ATENINTL_serial *a_serial;
-       __u16 minor;
-
-       a_serial = usb_get_serial_data(port->serial);
-       minor = port->serial->minor;
-       if (minor == SERIAL_TTY_NO_MINOR)
-               minor = 0;
-       val = val & 0x00ff;
-
-       /*
-        * For the UART control registers,
-        * the application number need to be Or'ed
-        */
-       if (a_serial->ATEN2011_spectrum_2or4ports == 4)
-               val |= (((__u16)port->number - minor) + 1) << 8;
-       else {
-               if (((__u16) port->number - minor) == 0)
-                       val |= (((__u16)port->number - minor) + 1) << 8;
-               else
-                       val |= (((__u16)port->number - minor) + 2) << 8;
-       }
-       dbg("%s: application number is %x", __func__, val);
-
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
-                              ATEN_WR_RTYPE, val, reg, NULL, 0,
-                              ATEN_WDR_TIMEOUT);
-}
-
-static int get_uart_reg(struct usb_serial_port *port, __u16 reg, __u16 *val)
-{
-       struct usb_device *dev = port->serial->dev;
-       int ret = 0;
-       __u16 wval;
-       struct ATENINTL_serial *a_serial;
-       __u16 minor = port->serial->minor;
-
-       a_serial = usb_get_serial_data(port->serial);
-       if (minor == SERIAL_TTY_NO_MINOR)
-               minor = 0;
-
-       /* wval is same as application number */
-       if (a_serial->ATEN2011_spectrum_2or4ports == 4)
-               wval = (((__u16)port->number - minor) + 1) << 8;
-       else {
-               if (((__u16) port->number - minor) == 0)
-                       wval = (((__u16) port->number - minor) + 1) << 8;
-               else
-                       wval = (((__u16) port->number - minor) + 2) << 8;
-       }
-       dbg("%s: application number is %x", __func__, wval);
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
-                             ATEN_RD_RTYPE, wval, reg, val, VENDOR_READ_LENGTH,
-                             ATEN_WDR_TIMEOUT);
-       *val = (*val) & 0x00ff;
-       return ret;
-}
-
-static int handle_newMsr(struct ATENINTL_port *port, __u8 newMsr)
-{
-       struct ATENINTL_port *ATEN2011_port;
-       struct async_icount *icount;
-       ATEN2011_port = port;
-       icount = &ATEN2011_port->icount;
-       if (newMsr &
-           (ATEN_MSR_DELTA_CTS | ATEN_MSR_DELTA_DSR | ATEN_MSR_DELTA_RI |
-            ATEN_MSR_DELTA_CD)) {
-               icount = &ATEN2011_port->icount;
-
-               /* update input line counters */
-               if (newMsr & ATEN_MSR_DELTA_CTS)
-                       icount->cts++;
-               if (newMsr & ATEN_MSR_DELTA_DSR)
-                       icount->dsr++;
-               if (newMsr & ATEN_MSR_DELTA_CD)
-                       icount->dcd++;
-               if (newMsr & ATEN_MSR_DELTA_RI)
-                       icount->rng++;
-       }
-
-       return 0;
-}
-
-static int handle_newLsr(struct ATENINTL_port *port, __u8 newLsr)
-{
-       struct async_icount *icount;
-
-       dbg("%s - %02x", __func__, newLsr);
-
-       if (newLsr & SERIAL_LSR_BI) {
-               /*
-                * Parity and Framing errors only count if they occur exclusive
-                * of a break being received.
-                */
-               newLsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
-       }
-
-       /* update input line counters */
-       icount = &port->icount;
-       if (newLsr & SERIAL_LSR_BI)
-               icount->brk++;
-       if (newLsr & SERIAL_LSR_OE)
-               icount->overrun++;
-       if (newLsr & SERIAL_LSR_PE)
-               icount->parity++;
-       if (newLsr & SERIAL_LSR_FE)
-               icount->frame++;
-
-       return 0;
-}
-
-static void ATEN2011_control_callback(struct urb *urb)
-{
-       unsigned char *data;
-       struct ATENINTL_port *ATEN2011_port;
-       __u8 regval = 0x0;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __func__,
-                   urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __func__,
-                   urb->status);
-               goto exit;
-       }
-
-       ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
-       dbg("%s urb buffer size is %d", __func__, urb->actual_length);
-       dbg("%s ATEN2011_port->MsrLsr is %d port %d", __func__,
-               ATEN2011_port->MsrLsr, ATEN2011_port->port_num);
-       data = urb->transfer_buffer;
-       regval = (__u8) data[0];
-       dbg("%s data is %x", __func__, regval);
-       if (ATEN2011_port->MsrLsr == 0)
-               handle_newMsr(ATEN2011_port, regval);
-       else if (ATEN2011_port->MsrLsr == 1)
-               handle_newLsr(ATEN2011_port, regval);
-
-exit:
-       return;
-}
-
-static int ATEN2011_get_reg(struct ATENINTL_port *ATEN, __u16 Wval, __u16 reg,
-                           __u16 *val)
-{
-       struct usb_device *dev = ATEN->port->serial->dev;
-       struct usb_ctrlrequest *dr = NULL;
-       unsigned char *buffer = NULL;
-       int ret = 0;
-       buffer = (__u8 *) ATEN->ctrl_buf;
-
-       dr = (void *)(buffer + 2);
-       dr->bRequestType = ATEN_RD_RTYPE;
-       dr->bRequest = ATEN_RDREQ;
-       dr->wValue = cpu_to_le16(Wval);
-       dr->wIndex = cpu_to_le16(reg);
-       dr->wLength = cpu_to_le16(2);
-
-       usb_fill_control_urb(ATEN->control_urb, dev, usb_rcvctrlpipe(dev, 0),
-                            (unsigned char *)dr, buffer, 2,
-                            ATEN2011_control_callback, ATEN);
-       ATEN->control_urb->transfer_buffer_length = 2;
-       ret = usb_submit_urb(ATEN->control_urb, GFP_ATOMIC);
-       return ret;
-}
-
-static void ATEN2011_interrupt_callback(struct urb *urb)
-{
-       int result;
-       int length;
-       struct ATENINTL_port *ATEN2011_port;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct usb_serial *serial;
-       __u16 Data;
-       unsigned char *data;
-       __u8 sp[5], st;
-       int i;
-       __u16 wval;
-       int minor;
-
-       dbg("%s", " : Entering");
-
-       ATEN2011_serial = (struct ATENINTL_serial *)urb->context;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __func__,
-                   urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __func__,
-                   urb->status);
-               goto exit;
-       }
-       length = urb->actual_length;
-       data = urb->transfer_buffer;
-
-       serial = ATEN2011_serial->serial;
-
-       /* ATENINTL get 5 bytes
-        * Byte 1 IIR Port 1 (port.number is 0)
-        * Byte 2 IIR Port 2 (port.number is 1)
-        * Byte 3 IIR Port 3 (port.number is 2)
-        * Byte 4 IIR Port 4 (port.number is 3)
-        * Byte 5 FIFO status for both */
-
-       if (length && length > 5) {
-               dbg("%s", "Wrong data !!!");
-               return;
-       }
-
-       /* MATRIX */
-       if (ATEN2011_serial->ATEN2011_spectrum_2or4ports == 4) {
-               sp[0] = (__u8) data[0];
-               sp[1] = (__u8) data[1];
-               sp[2] = (__u8) data[2];
-               sp[3] = (__u8) data[3];
-               st = (__u8) data[4];
-       } else {
-               sp[0] = (__u8) data[0];
-               sp[1] = (__u8) data[2];
-               /* sp[2]=(__u8)data[2]; */
-               /* sp[3]=(__u8)data[3]; */
-               st = (__u8) data[4];
-
-       }
-       for (i = 0; i < serial->num_ports; i++) {
-               ATEN2011_port = usb_get_serial_port_data(serial->port[i]);
-               minor = serial->minor;
-               if (minor == SERIAL_TTY_NO_MINOR)
-                       minor = 0;
-               if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
-                   && (i != 0))
-                       wval =
-                           (((__u16) serial->port[i]->number -
-                             (__u16) (minor)) + 2) << 8;
-               else
-                       wval =
-                           (((__u16) serial->port[i]->number -
-                             (__u16) (minor)) + 1) << 8;
-               if (ATEN2011_port->open != 0) {
-                       if (sp[i] & 0x01) {
-                               dbg("SP%d No Interrupt !!!", i);
-                       } else {
-                               switch (sp[i] & 0x0f) {
-                               case SERIAL_IIR_RLS:
-                                       dbg("Serial Port %d: Receiver status error or address bit detected in 9-bit mode", i);
-                                       ATEN2011_port->MsrLsr = 1;
-                                       ATEN2011_get_reg(ATEN2011_port, wval,
-                                                        LINE_STATUS_REGISTER,
-                                                        &Data);
-                                       break;
-                               case SERIAL_IIR_MS:
-                                       dbg("Serial Port %d: Modem status change", i);
-                                       ATEN2011_port->MsrLsr = 0;
-                                       ATEN2011_get_reg(ATEN2011_port, wval,
-                                                        MODEM_STATUS_REGISTER,
-                                                        &Data);
-                                       break;
-                               }
-                       }
-               }
-
-       }
-exit:
-       if (ATEN2011_serial->status_polling_started == 0)
-               return;
-
-       result = usb_submit_urb(urb, GFP_ATOMIC);
-       if (result) {
-               dev_err(&urb->dev->dev,
-                       "%s - Error %d submitting interrupt urb\n",
-                       __func__, result);
-       }
-
-       return;
-}
-
-static void ATEN2011_bulk_in_callback(struct urb *urb)
-{
-       int status;
-       unsigned char *data;
-       struct usb_serial *serial;
-       struct usb_serial_port *port;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct ATENINTL_port *ATEN2011_port;
-       struct tty_struct *tty;
-
-       if (urb->status) {
-               dbg("nonzero read bulk status received: %d", urb->status);
-               return;
-       }
-
-       ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
-       port = (struct usb_serial_port *)ATEN2011_port->port;
-       serial = port->serial;
-
-       dbg("%s", "Entering...");
-
-       data = urb->transfer_buffer;
-       ATEN2011_serial = usb_get_serial_data(serial);
-
-       if (urb->actual_length) {
-               tty = tty_port_tty_get(&ATEN2011_port->port->port);
-               if (tty) {
-                       tty_buffer_request_room(tty, urb->actual_length);
-                       tty_insert_flip_string(tty, data, urb->actual_length);
-                       tty_flip_buffer_push(tty);
-                       tty_kref_put(tty);
-               }
-
-               ATEN2011_port->icount.rx += urb->actual_length;
-               dbg("ATEN2011_port->icount.rx is %d:",
-                       ATEN2011_port->icount.rx);
-       }
-
-       if (!ATEN2011_port->read_urb) {
-               dbg("%s", "URB KILLED !!!");
-               return;
-       }
-
-       if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
-               ATEN2011_port->read_urb->dev = serial->dev;
-
-               status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
-               if (status)
-                       dbg("usb_submit_urb(read bulk) failed, status = %d", status);
-       }
-}
-
-static void ATEN2011_bulk_out_data_callback(struct urb *urb)
-{
-       struct ATENINTL_port *ATEN2011_port;
-       struct tty_struct *tty;
-
-       if (urb->status) {
-               dbg("nonzero write bulk status received:%d", urb->status);
-               return;
-       }
-
-       ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
-       dbg("%s", "Entering .........");
-
-       tty = tty_port_tty_get(&ATEN2011_port->port->port);
-
-       if (tty && ATEN2011_port->open)
-               /* tell the tty driver that something has changed */
-               tty_wakeup(tty);
-
-       /* schedule_work(&ATEN2011_port->port->work); */
-       tty_kref_put(tty);
-
-}
-
-#ifdef ATENSerialProbe
-static int ATEN2011_serial_probe(struct usb_serial *serial,
-                                const struct usb_device_id *id)
-{
-
-       /*need to implement the mode_reg reading and updating\
-          structures usb_serial_ device_type\
-          (i.e num_ports, num_bulkin,bulkout etc) */
-       /* Also we can update the changes  attach */
-       return 1;
-}
-#endif
-
-static int ATEN2011_open(struct tty_struct *tty, struct usb_serial_port *port,
-                        struct file *filp)
-{
-       int response;
-       int j;
-       struct usb_serial *serial;
-       struct urb *urb;
-       __u16 Data;
-       int status;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct ATENINTL_port *ATEN2011_port;
-       struct ktermios tmp_termios;
-       int minor;
-
-       serial = port->serial;
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return -ENODEV;
-
-       ATEN2011_serial = usb_get_serial_data(serial);
-       if (ATEN2011_serial == NULL)
-               return -ENODEV;
-
-       /* increment the number of opened ports counter here */
-       ATEN2011_serial->NoOfOpenPorts++;
-
-       usb_clear_halt(serial->dev, port->write_urb->pipe);
-       usb_clear_halt(serial->dev, port->read_urb->pipe);
-
-       /* Initialising the write urb pool */
-       for (j = 0; j < NUM_URBS; ++j) {
-               urb = usb_alloc_urb(0, GFP_ATOMIC);
-               ATEN2011_port->write_urb_pool[j] = urb;
-
-               if (urb == NULL) {
-                       err("No more urbs???");
-                       continue;
-               }
-
-               urb->transfer_buffer = NULL;
-               urb->transfer_buffer =
-                   kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-               if (!urb->transfer_buffer) {
-                       err("%s-out of memory for urb buffers.", __func__);
-                       continue;
-               }
-       }
-
-/*****************************************************************************
- * Initialize ATEN2011 -- Write Init values to corresponding Registers
- *
- * Register Index
- * 1 : IER
- * 2 : FCR
- * 3 : LCR
- * 4 : MCR
- *
- * 0x08 : SP1/2 Control Reg
- *****************************************************************************/
-
-/* NEED to check the fallowing Block */
-
-       Data = 0x0;
-       status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
-       if (status < 0) {
-               dbg("Reading Spreg failed");
-               return -1;
-       }
-       Data |= 0x80;
-       status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-       if (status < 0) {
-               dbg("writing Spreg failed");
-               return -1;
-       }
-
-       Data &= ~0x80;
-       status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-       if (status < 0) {
-               dbg("writing Spreg failed");
-               return -1;
-       }
-
-/* End of block to be checked */
-/**************************CHECK***************************/
-
-       if (RS485mode == 0)
-               Data = 0xC0;
-       else
-               Data = 0x00;
-       status = set_uart_reg(port, SCRATCH_PAD_REGISTER, Data);
-       if (status < 0) {
-               dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", status);
-               return -1;
-       } else
-               dbg("SCRATCH_PAD_REGISTER Writing success status%d", status);
-
-/**************************CHECK***************************/
-
-       Data = 0x0;
-       status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
-       if (status < 0) {
-               dbg("Reading Controlreg failed");
-               return -1;
-       }
-       Data |= 0x08;           /* Driver done bit */
-       Data |= 0x20;           /* rx_disable */
-       status = 0;
-       status =
-           set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
-       if (status < 0) {
-               dbg("writing Controlreg failed");
-               return -1;
-       }
-       /*
-        * do register settings here
-        * Set all regs to the device default values.
-        * First Disable all interrupts.
-        */
-
-       Data = 0x00;
-       status = set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-       if (status < 0) {
-               dbg("disableing interrupts failed");
-               return -1;
-       }
-       /* Set FIFO_CONTROL_REGISTER to the default value */
-       Data = 0x00;
-       status = set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-       if (status < 0) {
-               dbg("Writing FIFO_CONTROL_REGISTER  failed");
-               return -1;
-       }
-
-       Data = 0xcf;            /* chk */
-       status = set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-       if (status < 0) {
-               dbg("Writing FIFO_CONTROL_REGISTER  failed");
-               return -1;
-       }
-
-       Data = 0x03;            /* LCR_BITS_8 */
-       status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-       ATEN2011_port->shadowLCR = Data;
-
-       Data = 0x0b;            /* MCR_DTR|MCR_RTS|MCR_MASTER_IE */
-       status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-       ATEN2011_port->shadowMCR = Data;
-
-#ifdef Check
-       Data = 0x00;
-       status = get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
-       ATEN2011_port->shadowLCR = Data;
-
-       Data |= SERIAL_LCR_DLAB;        /* data latch enable in LCR 0x80 */
-       status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
-       Data = 0x0c;
-       status = set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
-
-       Data = 0x0;
-       status = set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
-
-       Data = 0x00;
-       status = get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
-
-/*      Data = ATEN2011_port->shadowLCR; */    /* data latch disable */
-       Data = Data & ~SERIAL_LCR_DLAB;
-       status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-       ATEN2011_port->shadowLCR = Data;
-#endif
-       /* clearing Bulkin and Bulkout Fifo */
-       Data = 0x0;
-       status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
-
-       Data = Data | 0x0c;
-       status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-
-       Data = Data & ~0x0c;
-       status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-       /* Finally enable all interrupts */
-       Data = 0x0;
-       Data = 0x0c;
-       status = set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
-       /* clearing rx_disable */
-       Data = 0x0;
-       status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
-       Data = Data & ~0x20;
-       status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
-
-       /* rx_negate */
-       Data = 0x0;
-       status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
-       Data = Data | 0x10;
-       status = 0;
-       status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
-
-       /*
-        * Check to see if we've set up our endpoint info yet
-        * (can't set it up in ATEN2011_startup as the structures
-        * were not set up at that time.)
-        */
-       if (ATEN2011_serial->NoOfOpenPorts == 1) {
-               /* start the status polling here */
-               ATEN2011_serial->status_polling_started = 1;
-               /* If not yet set, Set here */
-               ATEN2011_serial->interrupt_in_buffer =
-                   serial->port[0]->interrupt_in_buffer;
-               ATEN2011_serial->interrupt_in_endpoint =
-                   serial->port[0]->interrupt_in_endpointAddress;
-               ATEN2011_serial->interrupt_read_urb =
-                   serial->port[0]->interrupt_in_urb;
-
-               /* set up interrupt urb */
-               usb_fill_int_urb(ATEN2011_serial->interrupt_read_urb,
-                                serial->dev,
-                                usb_rcvintpipe(serial->dev,
-                                               ATEN2011_serial->
-                                               interrupt_in_endpoint),
-                                ATEN2011_serial->interrupt_in_buffer,
-                                ATEN2011_serial->interrupt_read_urb->
-                                transfer_buffer_length,
-                                ATEN2011_interrupt_callback, ATEN2011_serial,
-                                ATEN2011_serial->interrupt_read_urb->interval);
-
-               /* start interrupt read for ATEN2011               *
-                * will continue as long as ATEN2011 is connected  */
-
-               response =
-                   usb_submit_urb(ATEN2011_serial->interrupt_read_urb,
-                                  GFP_KERNEL);
-               if (response) {
-                       dbg("%s - Error %d submitting interrupt urb",
-                               __func__, response);
-               }
-
-       }
-
-       /*
-        * See if we've set up our endpoint info yet
-        * (can't set it up in ATEN2011_startup as the
-        * structures were not set up at that time.)
-        */
-
-       dbg("port number is %d", port->number);
-       dbg("serial number is %d", port->serial->minor);
-       dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
-       dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
-       dbg("Interrupt endpoint is %d",
-               port->interrupt_in_endpointAddress);
-       dbg("port's number in the device is %d", ATEN2011_port->port_num);
-       ATEN2011_port->bulk_in_buffer = port->bulk_in_buffer;
-       ATEN2011_port->bulk_in_endpoint = port->bulk_in_endpointAddress;
-       ATEN2011_port->read_urb = port->read_urb;
-       ATEN2011_port->bulk_out_endpoint = port->bulk_out_endpointAddress;
-
-       minor = port->serial->minor;
-       if (minor == SERIAL_TTY_NO_MINOR)
-               minor = 0;
-
-       /* set up our bulk in urb */
-       if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
-           && (((__u16) port->number - (__u16) (minor)) != 0)) {
-               usb_fill_bulk_urb(ATEN2011_port->read_urb, serial->dev,
-                                 usb_rcvbulkpipe(serial->dev,
-                                                 (port->
-                                                  bulk_in_endpointAddress +
-                                                  2)), port->bulk_in_buffer,
-                                 ATEN2011_port->read_urb->
-                                 transfer_buffer_length,
-                                 ATEN2011_bulk_in_callback, ATEN2011_port);
-       } else
-               usb_fill_bulk_urb(ATEN2011_port->read_urb,
-                                 serial->dev,
-                                 usb_rcvbulkpipe(serial->dev,
-                                                 port->
-                                                 bulk_in_endpointAddress),
-                                 port->bulk_in_buffer,
-                                 ATEN2011_port->read_urb->
-                                 transfer_buffer_length,
-                                 ATEN2011_bulk_in_callback, ATEN2011_port);
-
-       dbg("ATEN2011_open: bulkin endpoint is %d",
-               port->bulk_in_endpointAddress);
-       response = usb_submit_urb(ATEN2011_port->read_urb, GFP_KERNEL);
-       if (response) {
-               err("%s - Error %d submitting control urb", __func__,
-                   response);
-       }
-
-       /* initialize our wait queues */
-       init_waitqueue_head(&ATEN2011_port->wait_chase);
-       init_waitqueue_head(&ATEN2011_port->wait_command);
-
-       /* initialize our icount structure */
-       memset(&(ATEN2011_port->icount), 0x00, sizeof(ATEN2011_port->icount));
-
-       /* initialize our port settings */
-       ATEN2011_port->shadowMCR = MCR_MASTER_IE;       /* Must set to enable ints! */
-       ATEN2011_port->chaseResponsePending = 0;
-       /* send a open port command */
-       ATEN2011_port->open = 1;
-       /* ATEN2011_change_port_settings(ATEN2011_port,old_termios); */
-       /* Setup termios */
-       ATEN2011_set_termios(tty, port, &tmp_termios);
-       ATEN2011_port->icount.tx = 0;
-       ATEN2011_port->icount.rx = 0;
-
-       dbg("usb_serial serial:%x       ATEN2011_port:%x\nATEN2011_serial:%x      usb_serial_port port:%x",
-            (unsigned int)serial, (unsigned int)ATEN2011_port,
-            (unsigned int)ATEN2011_serial, (unsigned int)port);
-
-       return 0;
-
-}
-
-static int ATEN2011_chars_in_buffer(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       int i;
-       int chars = 0;
-       struct ATENINTL_port *ATEN2011_port;
-
-       /* dbg("%s"," ATEN2011_chars_in_buffer:entering ..........."); */
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-       if (ATEN2011_port == NULL) {
-               dbg("%s", "ATEN2011_break:leaving ...........");
-               return -1;
-       }
-
-       for (i = 0; i < NUM_URBS; ++i)
-               if (ATEN2011_port->write_urb_pool[i]->status == -EINPROGRESS)
-                       chars += URB_TRANSFER_BUFFER_SIZE;
-
-       dbg("%s - returns %d", __func__, chars);
-       return chars;
-
-}
-
-static void ATEN2011_block_until_tx_empty(struct tty_struct *tty,
-                                         struct ATENINTL_port *ATEN2011_port)
-{
-       int timeout = HZ / 10;
-       int wait = 30;
-       int count;
-
-       while (1) {
-               count = ATEN2011_chars_in_buffer(tty);
-
-               /* Check for Buffer status */
-               if (count <= 0)
-                       return;
-
-               /* Block the thread for a while */
-               interruptible_sleep_on_timeout(&ATEN2011_port->wait_chase,
-                                              timeout);
-
-               /* No activity.. count down section */
-               wait--;
-               if (wait == 0) {
-                       dbg("%s - TIMEOUT", __func__);
-                       return;
-               } else {
-                       /* Reset timout value back to seconds */
-                       wait = 30;
-               }
-       }
-}
-
-static void ATEN2011_close(struct tty_struct *tty, struct usb_serial_port *port,
-                          struct file *filp)
-{
-       struct usb_serial *serial;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct ATENINTL_port *ATEN2011_port;
-       int no_urbs;
-       __u16 Data;
-
-       dbg("%s", "ATEN2011_close:entering...");
-       serial = port->serial;
-
-       /* take the Adpater and port's private data */
-       ATEN2011_serial = usb_get_serial_data(serial);
-       ATEN2011_port = usb_get_serial_port_data(port);
-       if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
-               return;
-
-       if (serial->dev) {
-               /* flush and block(wait) until tx is empty */
-               ATEN2011_block_until_tx_empty(tty, ATEN2011_port);
-       }
-       /* kill the ports URB's */
-       for (no_urbs = 0; no_urbs < NUM_URBS; no_urbs++)
-               usb_kill_urb(ATEN2011_port->write_urb_pool[no_urbs]);
-       /* Freeing Write URBs */
-       for (no_urbs = 0; no_urbs < NUM_URBS; ++no_urbs) {
-               kfree(ATEN2011_port->write_urb_pool[no_urbs]->transfer_buffer);
-               usb_free_urb(ATEN2011_port->write_urb_pool[no_urbs]);
-       }
-       /* While closing port, shutdown all bulk read, write  *
-        * and interrupt read if they exists                  */
-       if (serial->dev) {
-               if (ATEN2011_port->write_urb) {
-                       dbg("%s", "Shutdown bulk write");
-                       usb_kill_urb(ATEN2011_port->write_urb);
-               }
-               if (ATEN2011_port->read_urb) {
-                       dbg("%s", "Shutdown bulk read");
-                       usb_kill_urb(ATEN2011_port->read_urb);
-               }
-               if ((&ATEN2011_port->control_urb)) {
-                       dbg("%s", "Shutdown control read");
-                       /* usb_kill_urb (ATEN2011_port->control_urb); */
-
-               }
-       }
-       /* if(ATEN2011_port->ctrl_buf != NULL) */
-               /* kfree(ATEN2011_port->ctrl_buf); */
-       /* decrement the no.of open ports counter of an individual USB-serial adapter. */
-       ATEN2011_serial->NoOfOpenPorts--;
-       dbg("NoOfOpenPorts in close%d:in port%d",
-               ATEN2011_serial->NoOfOpenPorts, port->number);
-       if (ATEN2011_serial->NoOfOpenPorts == 0) {
-               /* stop the stus polling here */
-               ATEN2011_serial->status_polling_started = 0;
-               if (ATEN2011_serial->interrupt_read_urb) {
-                       dbg("%s", "Shutdown interrupt_read_urb");
-                       /* ATEN2011_serial->interrupt_in_buffer=NULL; */
-                       /* usb_kill_urb (ATEN2011_serial->interrupt_read_urb); */
-               }
-       }
-       if (ATEN2011_port->write_urb) {
-               /* if this urb had a transfer buffer already (old tx) free it */
-               kfree(ATEN2011_port->write_urb->transfer_buffer);
-               usb_free_urb(ATEN2011_port->write_urb);
-       }
-
-       /* clear the MCR & IER */
-       Data = 0x00;
-       set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-       Data = 0x00;
-       set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
-       ATEN2011_port->open = 0;
-       dbg("%s", "Leaving ............");
-
-}
-
-static void ATEN2011_block_until_chase_response(struct tty_struct *tty,
-                                               struct ATENINTL_port
-                                               *ATEN2011_port)
-{
-       int timeout = 1 * HZ;
-       int wait = 10;
-       int count;
-
-       while (1) {
-               count = ATEN2011_chars_in_buffer(tty);
-
-               /* Check for Buffer status */
-               if (count <= 0) {
-                       ATEN2011_port->chaseResponsePending = 0;
-                       return;
-               }
-
-               /* Block the thread for a while */
-               interruptible_sleep_on_timeout(&ATEN2011_port->wait_chase,
-                                              timeout);
-               /* No activity.. count down section */
-               wait--;
-               if (wait == 0) {
-                       dbg("%s - TIMEOUT", __func__);
-                       return;
-               } else {
-                       /* Reset timout value back to seconds */
-                       wait = 10;
-               }
-       }
-
-}
-
-static void ATEN2011_break(struct tty_struct *tty, int break_state)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       unsigned char data;
-       struct usb_serial *serial;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct ATENINTL_port *ATEN2011_port;
-
-       dbg("%s", "Entering ...........");
-       dbg("ATEN2011_break: Start");
-
-       serial = port->serial;
-
-       ATEN2011_serial = usb_get_serial_data(serial);
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
-               return;
-
-       /* flush and chase */
-       ATEN2011_port->chaseResponsePending = 1;
-
-       if (serial->dev) {
-               /* flush and block until tx is empty */
-               ATEN2011_block_until_chase_response(tty, ATEN2011_port);
-       }
-
-       if (break_state == -1)
-               data = ATEN2011_port->shadowLCR | LCR_SET_BREAK;
-       else
-               data = ATEN2011_port->shadowLCR & ~LCR_SET_BREAK;
-
-       ATEN2011_port->shadowLCR = data;
-       dbg("ATEN2011_break ATEN2011_port->shadowLCR is %x",
-               ATEN2011_port->shadowLCR);
-       set_uart_reg(port, LINE_CONTROL_REGISTER, ATEN2011_port->shadowLCR);
-
-       return;
-}
-
-static int ATEN2011_write_room(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       int i;
-       int room = 0;
-       struct ATENINTL_port *ATEN2011_port;
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-       if (ATEN2011_port == NULL) {
-               dbg("%s", "ATEN2011_break:leaving ...........");
-               return -1;
-       }
-
-       for (i = 0; i < NUM_URBS; ++i)
-               if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS)
-                       room += URB_TRANSFER_BUFFER_SIZE;
-
-       dbg("%s - returns %d", __func__, room);
-       return room;
-
-}
-
-static int ATEN2011_write(struct tty_struct *tty, struct usb_serial_port *port,
-                         const unsigned char *data, int count)
-{
-       int status;
-       int i;
-       int bytes_sent = 0;
-       int transfer_size;
-       int minor;
-
-       struct ATENINTL_port *ATEN2011_port;
-       struct usb_serial *serial;
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct urb *urb;
-       const unsigned char *current_position = data;
-       unsigned char *data1;
-       dbg("%s", "entering ...........");
-
-       serial = port->serial;
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-       if (ATEN2011_port == NULL) {
-               dbg("%s", "ATEN2011_port is NULL");
-               return -1;
-       }
-
-       ATEN2011_serial = usb_get_serial_data(serial);
-       if (ATEN2011_serial == NULL) {
-               dbg("%s", "ATEN2011_serial is NULL");
-               return -1;
-       }
-
-       /* try to find a free urb in the list */
-       urb = NULL;
-
-       for (i = 0; i < NUM_URBS; ++i) {
-               if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS) {
-                       urb = ATEN2011_port->write_urb_pool[i];
-                       dbg("URB:%d", i);
-                       break;
-               }
-       }
-
-       if (urb == NULL) {
-               dbg("%s - no more free urbs", __func__);
-               goto exit;
-       }
-
-       if (urb->transfer_buffer == NULL) {
-               urb->transfer_buffer =
-                   kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-
-               if (urb->transfer_buffer == NULL) {
-                       err("%s no more kernel memory...", __func__);
-                       goto exit;
-               }
-       }
-       transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
-
-       memcpy(urb->transfer_buffer, current_position, transfer_size);
-       /* usb_serial_debug_data (__FILE__, __func__, transfer_size, urb->transfer_buffer); */
-
-       /* fill urb with data and submit  */
-       minor = port->serial->minor;
-       if (minor == SERIAL_TTY_NO_MINOR)
-               minor = 0;
-       if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
-           && (((__u16) port->number - (__u16) (minor)) != 0)) {
-               usb_fill_bulk_urb(urb, ATEN2011_serial->serial->dev,
-                                 usb_sndbulkpipe(ATEN2011_serial->serial->dev,
-                                                 (port->
-                                                  bulk_out_endpointAddress) +
-                                                 2), urb->transfer_buffer,
-                                 transfer_size,
-                                 ATEN2011_bulk_out_data_callback,
-                                 ATEN2011_port);
-       } else
-
-               usb_fill_bulk_urb(urb,
-                                 ATEN2011_serial->serial->dev,
-                                 usb_sndbulkpipe(ATEN2011_serial->serial->dev,
-                                                 port->
-                                                 bulk_out_endpointAddress),
-                                 urb->transfer_buffer, transfer_size,
-                                 ATEN2011_bulk_out_data_callback,
-                                 ATEN2011_port);
-
-       data1 = urb->transfer_buffer;
-       dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
-       /* for(i=0;i < urb->actual_length;i++) */
-               /* dbg("Data is %c ",data1[i]); */
-
-       /* send it down the pipe */
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-
-       if (status) {
-               err("%s - usb_submit_urb(write bulk) failed with status = %d",
-                   __func__, status);
-               bytes_sent = status;
-               goto exit;
-       }
-       bytes_sent = transfer_size;
-       ATEN2011_port->icount.tx += transfer_size;
-       dbg("ATEN2011_port->icount.tx is %d:", ATEN2011_port->icount.tx);
-
-exit:
-       return bytes_sent;
-}
-
-static void ATEN2011_throttle(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ATENINTL_port *ATEN2011_port;
-       int status;
-
-       dbg("- port %d", port->number);
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return;
-
-       if (!ATEN2011_port->open) {
-               dbg("%s", "port not opened");
-               return;
-       }
-
-       dbg("%s", "Entering .......... ");
-
-       if (!tty) {
-               dbg("%s - no tty available", __func__);
-               return;
-       }
-
-       /* if we are implementing XON/XOFF, send the stop character */
-       if (I_IXOFF(tty)) {
-               unsigned char stop_char = STOP_CHAR(tty);
-               status = ATEN2011_write(tty, port, &stop_char, 1);
-               if (status <= 0)
-                       return;
-       }
-
-       /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               ATEN2011_port->shadowMCR &= ~MCR_RTS;
-               status = set_uart_reg(port, MODEM_CONTROL_REGISTER,
-                                     ATEN2011_port->shadowMCR);
-               if (status < 0)
-                       return;
-       }
-
-       return;
-}
-
-static void ATEN2011_unthrottle(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       int status;
-       struct ATENINTL_port *ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return;
-
-       if (!ATEN2011_port->open) {
-               dbg("%s - port not opened", __func__);
-               return;
-       }
-
-       dbg("%s", "Entering .......... ");
-
-       if (!tty) {
-               dbg("%s - no tty available", __func__);
-               return;
-       }
-
-       /* if we are implementing XON/XOFF, send the start character */
-       if (I_IXOFF(tty)) {
-               unsigned char start_char = START_CHAR(tty);
-               status = ATEN2011_write(tty, port, &start_char, 1);
-               if (status <= 0)
-                       return;
-       }
-
-       /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               ATEN2011_port->shadowMCR |= MCR_RTS;
-               status = set_uart_reg(port, MODEM_CONTROL_REGISTER,
-                                     ATEN2011_port->shadowMCR);
-               if (status < 0)
-                       return;
-       }
-
-       return;
-}
-
-static int ATEN2011_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ATENINTL_port *ATEN2011_port;
-       unsigned int result;
-       __u16 msr;
-       __u16 mcr;
-       /* unsigned int mcr; */
-       int status = 0;
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       dbg("%s - port %d", __func__, port->number);
-
-       if (ATEN2011_port == NULL)
-               return -ENODEV;
-
-       status = get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
-       status = get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
-       /* mcr = ATEN2011_port->shadowMCR; */
-       /* COMMENT2: the Fallowing three line are commented for updating only MSR values */
-       result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
-           | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
-           | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
-           | ((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS : 0)
-           | ((msr & ATEN2011_MSR_CD) ? TIOCM_CAR : 0)
-           | ((msr & ATEN2011_MSR_RI) ? TIOCM_RI : 0)
-           | ((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR : 0);
-
-       dbg("%s - 0x%04X", __func__, result);
-
-       return result;
-}
-
-static int ATEN2011_tiocmset(struct tty_struct *tty, struct file *file,
-                            unsigned int set, unsigned int clear)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ATENINTL_port *ATEN2011_port;
-       unsigned int mcr;
-       unsigned int status;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return -ENODEV;
-
-       mcr = ATEN2011_port->shadowMCR;
-       if (clear & TIOCM_RTS)
-               mcr &= ~MCR_RTS;
-       if (clear & TIOCM_DTR)
-               mcr &= ~MCR_DTR;
-       if (clear & TIOCM_LOOP)
-               mcr &= ~MCR_LOOPBACK;
-
-       if (set & TIOCM_RTS)
-               mcr |= MCR_RTS;
-       if (set & TIOCM_DTR)
-               mcr |= MCR_DTR;
-       if (set & TIOCM_LOOP)
-               mcr |= MCR_LOOPBACK;
-
-       ATEN2011_port->shadowMCR = mcr;
-
-       status = set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
-       if (status < 0) {
-               dbg("setting MODEM_CONTROL_REGISTER Failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void ATEN2011_set_termios(struct tty_struct *tty,
-                                struct usb_serial_port *port,
-                                struct ktermios *old_termios)
-{
-       int status;
-       unsigned int cflag;
-       struct usb_serial *serial;
-       struct ATENINTL_port *ATEN2011_port;
-
-       dbg("ATEN2011_set_termios: START");
-
-       serial = port->serial;
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return;
-
-       if (!ATEN2011_port->open) {
-               dbg("%s - port not opened", __func__);
-               return;
-       }
-
-       dbg("%s", "setting termios - ");
-
-       cflag = tty->termios->c_cflag;
-
-       dbg("%s - cflag %08x iflag %08x", __func__,
-           tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
-
-       if (old_termios) {
-               dbg("%s - old clfag %08x old iflag %08x", __func__,
-                   old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
-       }
-
-       dbg("%s - port %d", __func__, port->number);
-
-       /* change the port settings to the new ones specified */
-
-       ATEN2011_change_port_settings(tty, ATEN2011_port, old_termios);
-
-       if (!ATEN2011_port->read_urb) {
-               dbg("%s", "URB KILLED !!!!!");
-               return;
-       }
-
-       if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
-               ATEN2011_port->read_urb->dev = serial->dev;
-               status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
-               if (status) {
-                       dbg
-                           (" usb_submit_urb(read bulk) failed, status = %d",
-                            status);
-               }
-       }
-       return;
-}
-
-static int get_lsr_info(struct tty_struct *tty,
-                       struct ATENINTL_port *ATEN2011_port,
-                       unsigned int __user *value)
-{
-       int count;
-       unsigned int result = 0;
-
-       count = ATEN2011_chars_in_buffer(tty);
-       if (count == 0) {
-               dbg("%s -- Empty", __func__);
-               result = TIOCSER_TEMT;
-       }
-
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-       return 0;
-}
-
-static int get_number_bytes_avail(struct tty_struct *tty,
-                                 struct ATENINTL_port *ATEN2011_port,
-                                 unsigned int __user *value)
-{
-       unsigned int result = 0;
-
-       if (!tty)
-               return -ENOIOCTLCMD;
-
-       result = tty->read_cnt;
-
-       dbg("%s(%d) = %d", __func__, ATEN2011_port->port->number, result);
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-
-       return -ENOIOCTLCMD;
-}
-
-static int set_modem_info(struct ATENINTL_port *ATEN2011_port, unsigned int cmd,
-                         unsigned int __user *value)
-{
-       unsigned int mcr;
-       unsigned int arg;
-       __u16 Data;
-       int status;
-       struct usb_serial_port *port;
-
-       if (ATEN2011_port == NULL)
-               return -1;
-
-       port = (struct usb_serial_port *)ATEN2011_port->port;
-
-       mcr = ATEN2011_port->shadowMCR;
-
-       if (copy_from_user(&arg, value, sizeof(int)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case TIOCMBIS:
-               if (arg & TIOCM_RTS)
-                       mcr |= MCR_RTS;
-               if (arg & TIOCM_DTR)
-                       mcr |= MCR_RTS;
-               if (arg & TIOCM_LOOP)
-                       mcr |= MCR_LOOPBACK;
-               break;
-
-       case TIOCMBIC:
-               if (arg & TIOCM_RTS)
-                       mcr &= ~MCR_RTS;
-               if (arg & TIOCM_DTR)
-                       mcr &= ~MCR_RTS;
-               if (arg & TIOCM_LOOP)
-                       mcr &= ~MCR_LOOPBACK;
-               break;
-
-       case TIOCMSET:
-               /* turn off the RTS and DTR and LOOPBACK
-                * and then only turn on what was asked to */
-               mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
-               mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
-               mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
-               mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
-               break;
-       }
-
-       ATEN2011_port->shadowMCR = mcr;
-
-       Data = ATEN2011_port->shadowMCR;
-       status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-       if (status < 0) {
-               dbg("setting MODEM_CONTROL_REGISTER Failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int get_modem_info(struct ATENINTL_port *ATEN2011_port,
-                         unsigned int __user *value)
-{
-       unsigned int result = 0;
-       __u16 msr;
-       unsigned int mcr = ATEN2011_port->shadowMCR;
-       int status;
-
-       status = get_uart_reg(ATEN2011_port->port, MODEM_STATUS_REGISTER, &msr);
-       result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)      /* 0x002 */
-           |((mcr & MCR_RTS) ? TIOCM_RTS : 0)  /* 0x004 */
-           |((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
-           |((msr & ATEN2011_MSR_CD) ? TIOCM_CAR : 0)  /* 0x040 */
-           |((msr & ATEN2011_MSR_RI) ? TIOCM_RI : 0)   /* 0x080 */
-           |((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR : 0);        /* 0x100 */
-
-       dbg("%s -- %x", __func__, result);
-
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-       return 0;
-}
-
-static int get_serial_info(struct ATENINTL_port *ATEN2011_port,
-                          struct serial_struct __user *retinfo)
-{
-       struct serial_struct tmp;
-
-       if (ATEN2011_port == NULL)
-               return -1;
-
-       if (!retinfo)
-               return -EFAULT;
-
-       memset(&tmp, 0, sizeof(tmp));
-
-       tmp.type = PORT_16550A;
-       tmp.line = ATEN2011_port->port->serial->minor;
-       if (tmp.line == SERIAL_TTY_NO_MINOR)
-               tmp.line = 0;
-       tmp.port = ATEN2011_port->port->number;
-       tmp.irq = 0;
-       tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
-       tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
-       tmp.baud_base = 9600;
-       tmp.close_delay = 5 * HZ;
-       tmp.closing_wait = 30 * HZ;
-
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int ATEN2011_ioctl(struct tty_struct *tty, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ATENINTL_port *ATEN2011_port;
-       struct async_icount cnow;
-       struct async_icount cprev;
-       struct serial_icounter_struct icount;
-       int ATENret = 0;
-       unsigned int __user *user_arg = (unsigned int __user *)arg;
-
-       ATEN2011_port = usb_get_serial_port_data(port);
-
-       if (ATEN2011_port == NULL)
-               return -1;
-
-       dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
-
-       switch (cmd) {
-               /* return number of bytes available */
-
-       case TIOCINQ:
-               dbg("%s (%d) TIOCINQ", __func__, port->number);
-               return get_number_bytes_avail(tty, ATEN2011_port, user_arg);
-               break;
-
-       case TIOCOUTQ:
-               dbg("%s (%d) TIOCOUTQ", __func__, port->number);
-               return put_user(ATEN2011_chars_in_buffer(tty), user_arg);
-               break;
-
-       case TIOCSERGETLSR:
-               dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
-               return get_lsr_info(tty, ATEN2011_port, user_arg);
-               return 0;
-
-       case TIOCMBIS:
-       case TIOCMBIC:
-       case TIOCMSET:
-               dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
-                   port->number);
-               ATENret = set_modem_info(ATEN2011_port, cmd, user_arg);
-               return ATENret;
-
-       case TIOCMGET:
-               dbg("%s (%d) TIOCMGET", __func__, port->number);
-               return get_modem_info(ATEN2011_port, user_arg);
-
-       case TIOCGSERIAL:
-               dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
-               return get_serial_info(ATEN2011_port,
-                                      (struct serial_struct __user *)arg);
-
-       case TIOCSSERIAL:
-               dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
-               break;
-
-       case TIOCMIWAIT:
-               dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
-               cprev = ATEN2011_port->icount;
-               while (1) {
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-                       cnow = ATEN2011_port->icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO;    /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* NOTREACHED */
-               break;
-
-       case TIOCGICOUNT:
-               cnow = ATEN2011_port->icount;
-               icount.cts = cnow.cts;
-               icount.dsr = cnow.dsr;
-               icount.rng = cnow.rng;
-               icount.dcd = cnow.dcd;
-               icount.rx = cnow.rx;
-               icount.tx = cnow.tx;
-               icount.frame = cnow.frame;
-               icount.overrun = cnow.overrun;
-               icount.parity = cnow.parity;
-               icount.brk = cnow.brk;
-               icount.buf_overrun = cnow.buf_overrun;
-
-               dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
-                   port->number, icount.rx, icount.tx);
-               if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
-                       return -EFAULT;
-               return 0;
-
-       default:
-               break;
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-static int ATEN2011_calc_baud_rate_divisor(int baudRate, int *divisor,
-                                          __u16 *clk_sel_val)
-{
-       dbg("%s - %d", __func__, baudRate);
-
-       if (baudRate <= 115200) {
-               *divisor = 115200 / baudRate;
-               *clk_sel_val = 0x0;
-       }
-       if ((baudRate > 115200) && (baudRate <= 230400)) {
-               *divisor = 230400 / baudRate;
-               *clk_sel_val = 0x10;
-       } else if ((baudRate > 230400) && (baudRate <= 403200)) {
-               *divisor = 403200 / baudRate;
-               *clk_sel_val = 0x20;
-       } else if ((baudRate > 403200) && (baudRate <= 460800)) {
-               *divisor = 460800 / baudRate;
-               *clk_sel_val = 0x30;
-       } else if ((baudRate > 460800) && (baudRate <= 806400)) {
-               *divisor = 806400 / baudRate;
-               *clk_sel_val = 0x40;
-       } else if ((baudRate > 806400) && (baudRate <= 921600)) {
-               *divisor = 921600 / baudRate;
-               *clk_sel_val = 0x50;
-       } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
-               *divisor = 1572864 / baudRate;
-               *clk_sel_val = 0x60;
-       } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
-               *divisor = 3145728 / baudRate;
-               *clk_sel_val = 0x70;
-       }
-       return 0;
-}
-
-static int ATEN2011_send_cmd_write_baud_rate(struct ATENINTL_port
-                                            *ATEN2011_port, int baudRate)
-{
-       int divisor = 0;
-       int status;
-       __u16 Data;
-       unsigned char number;
-       __u16 clk_sel_val;
-       struct usb_serial_port *port;
-       int minor;
-
-       if (ATEN2011_port == NULL)
-               return -1;
-
-       port = (struct usb_serial_port *)ATEN2011_port->port;
-
-       dbg("%s", "Entering .......... ");
-
-       minor = ATEN2011_port->port->serial->minor;
-       if (minor == SERIAL_TTY_NO_MINOR)
-               minor = 0;
-       number = ATEN2011_port->port->number - minor;
-
-       dbg("%s - port = %d, baud = %d", __func__,
-           ATEN2011_port->port->number, baudRate);
-       /* reset clk_uart_sel in spregOffset */
-       if (baudRate > 115200) {
-#ifdef HW_flow_control
-               /*
-                * NOTE: need to see the pther register to modify
-                * setting h/w flow control bit to 1;
-                */
-               /* Data = ATEN2011_port->shadowMCR; */
-               Data = 0x2b;
-               ATEN2011_port->shadowMCR = Data;
-               status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-               if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud");
-                       return -1;
-               }
-#endif
-
-       } else {
-#ifdef HW_flow_control
-               /* setting h/w flow control bit to 0; */
-               /* Data = ATEN2011_port->shadowMCR; */
-               Data = 0xb;
-               ATEN2011_port->shadowMCR = Data;
-               status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-               if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud");
-                       return -1;
-               }
-#endif
-
-       }
-
-       if (1)                  /* baudRate <= 115200) */ {
-               clk_sel_val = 0x0;
-               Data = 0x0;
-               status =
-                   ATEN2011_calc_baud_rate_divisor(baudRate, &divisor,
-                                                   &clk_sel_val);
-               status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
-               if (status < 0) {
-                       dbg("reading spreg failed in set_serial_baud");
-                       return -1;
-               }
-               Data = (Data & 0x8f) | clk_sel_val;
-               status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-               if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud");
-                       return -1;
-               }
-               /* Calculate the Divisor */
-
-               if (status) {
-                       err("%s - bad baud rate", __func__);
-                       dbg("%s", "bad baud rate");
-                       return status;
-               }
-               /* Enable access to divisor latch */
-               Data = ATEN2011_port->shadowLCR | SERIAL_LCR_DLAB;
-               ATEN2011_port->shadowLCR = Data;
-               set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
-               /* Write the divisor */
-               Data = (unsigned char)(divisor & 0xff);
-               dbg("set_serial_baud Value to write DLL is %x", Data);
-               set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
-
-               Data = (unsigned char)((divisor & 0xff00) >> 8);
-               dbg("set_serial_baud Value to write DLM is %x", Data);
-               set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
-
-               /* Disable access to divisor latch */
-               Data = ATEN2011_port->shadowLCR & ~SERIAL_LCR_DLAB;
-               ATEN2011_port->shadowLCR = Data;
-               set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
-       }
-
-       return status;
-}
-
-static void ATEN2011_change_port_settings(struct tty_struct *tty,
-                                         struct ATENINTL_port *ATEN2011_port,
-                                         struct ktermios *old_termios)
-{
-       int baud;
-       unsigned cflag;
-       unsigned iflag;
-       __u8 lData;
-       __u8 lParity;
-       __u8 lStop;
-       int status;
-       __u16 Data;
-       struct usb_serial_port *port;
-       struct usb_serial *serial;
-
-       if (ATEN2011_port == NULL)
-               return;
-
-       port = (struct usb_serial_port *)ATEN2011_port->port;
-
-       serial = port->serial;
-
-       dbg("%s - port %d", __func__, ATEN2011_port->port->number);
-
-       if (!ATEN2011_port->open) {
-               dbg("%s - port not opened", __func__);
-               return;
-       }
-
-       if ((!tty) || (!tty->termios)) {
-               dbg("%s - no tty structures", __func__);
-               return;
-       }
-
-       dbg("%s", "Entering .......... ");
-
-       lData = LCR_BITS_8;
-       lStop = LCR_STOP_1;
-       lParity = LCR_PAR_NONE;
-
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
-
-       /* Change the number of bits */
-
-       /* COMMENT1: the below Line"if(cflag & CSIZE)" is added for the errors we get for serial loop data test i.e serial_loopback.pl -v */
-       /* if(cflag & CSIZE) */
-       {
-               switch (cflag & CSIZE) {
-               case CS5:
-                       lData = LCR_BITS_5;
-                       break;
-
-               case CS6:
-                       lData = LCR_BITS_6;
-                       break;
-
-               case CS7:
-                       lData = LCR_BITS_7;
-                       break;
-               default:
-               case CS8:
-                       lData = LCR_BITS_8;
-                       break;
-               }
-       }
-       /* Change the Parity bit */
-       if (cflag & PARENB) {
-               if (cflag & PARODD) {
-                       lParity = LCR_PAR_ODD;
-                       dbg("%s - parity = odd", __func__);
-               } else {
-                       lParity = LCR_PAR_EVEN;
-                       dbg("%s - parity = even", __func__);
-               }
-
-       } else {
-               dbg("%s - parity = none", __func__);
-       }
-
-       if (cflag & CMSPAR)
-               lParity = lParity | 0x20;
-
-       /* Change the Stop bit */
-       if (cflag & CSTOPB) {
-               lStop = LCR_STOP_2;
-               dbg("%s - stop bits = 2", __func__);
-       } else {
-               lStop = LCR_STOP_1;
-               dbg("%s - stop bits = 1", __func__);
-       }
-
-       /* Update the LCR with the correct value */
-       ATEN2011_port->shadowLCR &=
-           ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
-       ATEN2011_port->shadowLCR |= (lData | lParity | lStop);
-
-       dbg
-           ("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is %x",
-            ATEN2011_port->shadowLCR);
-       /* Disable Interrupts */
-       Data = 0x00;
-       set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
-       Data = 0x00;
-       set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-
-       Data = 0xcf;
-       set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-
-       /* Send the updated LCR value to the ATEN2011 */
-       Data = ATEN2011_port->shadowLCR;
-
-       set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
-       Data = 0x00b;
-       ATEN2011_port->shadowMCR = Data;
-       set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-       Data = 0x00b;
-       set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-
-       /* set up the MCR register and send it to the ATEN2011 */
-
-       ATEN2011_port->shadowMCR = MCR_MASTER_IE;
-       if (cflag & CBAUD)
-               ATEN2011_port->shadowMCR |= (MCR_DTR | MCR_RTS);
-
-       if (cflag & CRTSCTS)
-               ATEN2011_port->shadowMCR |= (MCR_XON_ANY);
-       else
-               ATEN2011_port->shadowMCR &= ~(MCR_XON_ANY);
-
-       Data = ATEN2011_port->shadowMCR;
-       set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-
-       /* Determine divisor based on baud rate */
-       baud = tty_get_baud_rate(tty);
-
-       if (!baud) {
-               /* pick a default, any default... */
-               dbg("%s", "Picked default baud...");
-               baud = 9600;
-       }
-
-       dbg("%s - baud rate = %d", __func__, baud);
-       status = ATEN2011_send_cmd_write_baud_rate(ATEN2011_port, baud);
-
-       /* Enable Interrupts */
-       Data = 0x0c;
-       set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
-       if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
-               ATEN2011_port->read_urb->dev = serial->dev;
-
-               status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
-
-               if (status) {
-                       dbg
-                           (" usb_submit_urb(read bulk) failed, status = %d",
-                            status);
-               }
-       }
-       dbg
-           ("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is End %x",
-            ATEN2011_port->shadowLCR);
-
-       return;
-}
-
-static int ATEN2011_calc_num_ports(struct usb_serial *serial)
-{
-
-       __u16 Data = 0x00;
-       int ret = 0;
-       int ATEN2011_2or4ports;
-       ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-                             ATEN_RDREQ, ATEN_RD_RTYPE, 0, GPIO_REGISTER,
-                             &Data, VENDOR_READ_LENGTH, ATEN_WDR_TIMEOUT);
-
-/* ghostgum: here is where the problem appears to bet */
-/* Which of the following are needed? */
-/* Greg used the serial->type->num_ports=2 */
-/* But the code in the ATEN2011_open relies on serial->num_ports=2 */
-       if ((Data & 0x01) == 0) {
-               ATEN2011_2or4ports = 2;
-               serial->type->num_ports = 2;
-               serial->num_ports = 2;
-       }
-       /* else if(serial->interface->cur_altsetting->desc.bNumEndpoints == 9) */
-       else {
-               ATEN2011_2or4ports = 4;
-               serial->type->num_ports = 4;
-               serial->num_ports = 4;
-
-       }
-
-       return ATEN2011_2or4ports;
-}
-
-static int ATEN2011_startup(struct usb_serial *serial)
-{
-       struct ATENINTL_serial *ATEN2011_serial;
-       struct ATENINTL_port *ATEN2011_port;
-       struct usb_device *dev;
-       int i, status;
-       int minor;
-
-       __u16 Data;
-       dbg("%s", " ATEN2011_startup :entering..........");
-
-       if (!serial) {
-               dbg("%s", "Invalid Handler");
-               return -1;
-       }
-
-       dev = serial->dev;
-
-       dbg("%s", "Entering...");
-
-       /* create our private serial structure */
-       ATEN2011_serial = kzalloc(sizeof(struct ATENINTL_serial), GFP_KERNEL);
-       if (ATEN2011_serial == NULL) {
-               err("%s - Out of memory", __func__);
-               return -ENOMEM;
-       }
-
-       /* resetting the private structure field values to zero */
-       memset(ATEN2011_serial, 0, sizeof(struct ATENINTL_serial));
-
-       ATEN2011_serial->serial = serial;
-       /* initilize status polling flag to 0 */
-       ATEN2011_serial->status_polling_started = 0;
-
-       usb_set_serial_data(serial, ATEN2011_serial);
-       ATEN2011_serial->ATEN2011_spectrum_2or4ports =
-           ATEN2011_calc_num_ports(serial);
-       /* we set up the pointers to the endpoints in the ATEN2011_open *
-        * function, as the structures aren't created yet.             */
-
-       /* set up port private structures */
-       for (i = 0; i < serial->num_ports; ++i) {
-               ATEN2011_port =
-                   kmalloc(sizeof(struct ATENINTL_port), GFP_KERNEL);
-               if (ATEN2011_port == NULL) {
-                       err("%s - Out of memory", __func__);
-                       usb_set_serial_data(serial, NULL);
-                       kfree(ATEN2011_serial);
-                       return -ENOMEM;
-               }
-               memset(ATEN2011_port, 0, sizeof(struct ATENINTL_port));
-
-               /*
-                * Initialize all port interrupt end point to port 0
-                * int endpoint. Our device has only one interrupt end point
-                * comman to all port
-                */
-               /* serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; */
-
-               ATEN2011_port->port = serial->port[i];
-               usb_set_serial_port_data(serial->port[i], ATEN2011_port);
-
-               minor = serial->port[i]->serial->minor;
-               if (minor == SERIAL_TTY_NO_MINOR)
-                       minor = 0;
-               ATEN2011_port->port_num =
-                   ((serial->port[i]->number - minor) + 1);
-
-               if (ATEN2011_port->port_num == 1) {
-                       ATEN2011_port->SpRegOffset = 0x0;
-                       ATEN2011_port->ControlRegOffset = 0x1;
-                       ATEN2011_port->DcrRegOffset = 0x4;
-               } else if ((ATEN2011_port->port_num == 2)
-                          && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
-                              4)) {
-                       ATEN2011_port->SpRegOffset = 0x8;
-                       ATEN2011_port->ControlRegOffset = 0x9;
-                       ATEN2011_port->DcrRegOffset = 0x16;
-               } else if ((ATEN2011_port->port_num == 2)
-                          && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
-                              2)) {
-                       ATEN2011_port->SpRegOffset = 0xa;
-                       ATEN2011_port->ControlRegOffset = 0xb;
-                       ATEN2011_port->DcrRegOffset = 0x19;
-               } else if ((ATEN2011_port->port_num == 3)
-                          && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
-                              4)) {
-                       ATEN2011_port->SpRegOffset = 0xa;
-                       ATEN2011_port->ControlRegOffset = 0xb;
-                       ATEN2011_port->DcrRegOffset = 0x19;
-               } else if ((ATEN2011_port->port_num == 4)
-                          && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
-                              4)) {
-                       ATEN2011_port->SpRegOffset = 0xc;
-                       ATEN2011_port->ControlRegOffset = 0xd;
-                       ATEN2011_port->DcrRegOffset = 0x1c;
-               }
-
-               usb_set_serial_port_data(serial->port[i], ATEN2011_port);
-
-               /* enable rx_disable bit in control register */
-
-               status = get_reg_sync(serial->port[i],
-                                     ATEN2011_port->ControlRegOffset, &Data);
-               if (status < 0) {
-                       dbg("Reading ControlReg failed status-0x%x",
-                               status);
-                       break;
-               } else
-                       dbg
-                           ("ControlReg Reading success val is %x, status%d",
-                            Data, status);
-               Data |= 0x08;   /* setting driver done bit */
-               Data |= 0x04;   /* sp1_bit to have cts change reflect in modem status reg */
-
-               /* Data |= 0x20; */     /* rx_disable bit */
-               status = set_reg_sync(serial->port[i],
-                                     ATEN2011_port->ControlRegOffset, Data);
-               if (status < 0) {
-                       dbg
-                           ("Writing ControlReg failed(rx_disable) status-0x%x",
-                            status);
-                       break;
-               } else
-                       dbg
-                           ("ControlReg Writing success(rx_disable) status%d",
-                            status);
-
-               /*
-                * Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
-                * and 0x24 in DCR3
-                */
-               Data = 0x01;
-               status = set_reg_sync(serial->port[i],
-                                     (__u16)(ATEN2011_port->DcrRegOffset + 0),
-                                     Data);
-               if (status < 0) {
-                       dbg("Writing DCR0 failed status-0x%x", status);
-                       break;
-               } else
-                       dbg("DCR0 Writing success status%d", status);
-
-               Data = 0x05;
-               status = set_reg_sync(serial->port[i],
-                                     (__u16)(ATEN2011_port->DcrRegOffset + 1),
-                                     Data);
-               if (status < 0) {
-                       dbg("Writing DCR1 failed status-0x%x", status);
-                       break;
-               } else
-                       dbg("DCR1 Writing success status%d", status);
-
-               Data = 0x24;
-               status = set_reg_sync(serial->port[i],
-                                     (__u16)(ATEN2011_port->DcrRegOffset + 2),
-                                     Data);
-               if (status < 0) {
-                       dbg("Writing DCR2 failed status-0x%x", status);
-                       break;
-               } else
-                       dbg("DCR2 Writing success status%d", status);
-
-               /* write values in clkstart0x0 and clkmulti 0x20 */
-               Data = 0x0;
-               status = set_reg_sync(serial->port[i], CLK_START_VALUE_REGISTER,
-                                     Data);
-               if (status < 0) {
-                       dbg
-                           ("Writing CLK_START_VALUE_REGISTER failed status-0x%x",
-                            status);
-                       break;
-               } else
-                       dbg
-                           ("CLK_START_VALUE_REGISTER Writing success status%d",
-                            status);
-
-               Data = 0x20;
-               status = set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
-                                     Data);
-               if (status < 0) {
-                       dbg
-                           ("Writing CLK_MULTI_REGISTER failed status-0x%x",
-                            status);
-                       break;
-               } else
-                       dbg("CLK_MULTI_REGISTER Writing success status%d",
-                               status);
-
-               /* Zero Length flag register */
-               if ((ATEN2011_port->port_num != 1)
-                   && (ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)) {
-
-                       Data = 0xff;
-                       status = set_reg_sync(serial->port[i],
-                                             (__u16)(ZLP_REG1 + ((__u16)ATEN2011_port->port_num)),
-                                             Data);
-                       dbg("ZLIP offset%x",
-                               (__u16) (ZLP_REG1 +
-                                        ((__u16) ATEN2011_port->port_num)));
-                       if (status < 0) {
-                               dbg
-                                   ("Writing ZLP_REG%d failed status-0x%x",
-                                    i + 2, status);
-                               break;
-                       } else
-                               dbg("ZLP_REG%d Writing success status%d",
-                                       i + 2, status);
-               } else {
-                       Data = 0xff;
-                       status = set_reg_sync(serial->port[i],
-                                             (__u16)(ZLP_REG1 + ((__u16)ATEN2011_port->port_num) - 0x1),
-                                             Data);
-                       dbg("ZLIP offset%x",
-                               (__u16) (ZLP_REG1 +
-                                        ((__u16) ATEN2011_port->port_num) -
-                                        0x1));
-                       if (status < 0) {
-                               dbg
-                                   ("Writing ZLP_REG%d failed status-0x%x",
-                                    i + 1, status);
-                               break;
-                       } else
-                               dbg("ZLP_REG%d Writing success status%d",
-                                       i + 1, status);
-
-               }
-               ATEN2011_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC);
-               ATEN2011_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
-
-       }
-
-       /* Zero Length flag enable */
-       Data = 0x0f;
-       status = set_reg_sync(serial->port[0], ZLP_REG5, Data);
-       if (status < 0) {
-               dbg("Writing ZLP_REG5 failed status-0x%x", status);
-               return -1;
-       } else
-               dbg("ZLP_REG5 Writing success status%d", status);
-
-       /* setting configuration feature to one */
-       usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                       (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
-       return 0;
-}
-
-static void ATEN2011_release(struct usb_serial *serial)
-{
-       int i;
-       struct ATENINTL_port *ATEN2011_port;
-
-       /* check for the ports to be closed,close the ports and disconnect */
-
-       /* free private structure allocated for serial port  *
-        * stop reads and writes on all ports                */
-
-       for (i = 0; i < serial->num_ports; ++i) {
-               ATEN2011_port = usb_get_serial_port_data(serial->port[i]);
-               kfree(ATEN2011_port->ctrl_buf);
-               usb_kill_urb(ATEN2011_port->control_urb);
-               kfree(ATEN2011_port);
-               usb_set_serial_port_data(serial->port[i], NULL);
-       }
-
-       /* free private structure allocated for serial device */
-
-       kfree(usb_get_serial_data(serial));
-       usb_set_serial_data(serial, NULL);
-}
-
-static struct usb_serial_driver aten_serial_driver = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "aten2011",
-               },
-       .description =          DRIVER_DESC,
-       .id_table =             id_table,
-       .open =                 ATEN2011_open,
-       .close =                ATEN2011_close,
-       .write =                ATEN2011_write,
-       .write_room =           ATEN2011_write_room,
-       .chars_in_buffer =      ATEN2011_chars_in_buffer,
-       .throttle =             ATEN2011_throttle,
-       .unthrottle =           ATEN2011_unthrottle,
-       .calc_num_ports =       ATEN2011_calc_num_ports,
-
-       .ioctl =                ATEN2011_ioctl,
-       .set_termios =          ATEN2011_set_termios,
-       .break_ctl =            ATEN2011_break,
-       .tiocmget =             ATEN2011_tiocmget,
-       .tiocmset =             ATEN2011_tiocmset,
-       .attach =               ATEN2011_startup,
-       .release =              ATEN2011_release,
-       .read_bulk_callback =   ATEN2011_bulk_in_callback,
-       .read_int_callback =    ATEN2011_interrupt_callback,
-};
-
-static struct usb_driver aten_driver = {
-       .name =         "aten2011",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table,
-};
-
-static int __init aten_init(void)
-{
-       int retval;
-
-       /* Register with the usb serial */
-       retval = usb_serial_register(&aten_serial_driver);
-       if (retval)
-               return retval;
-
-       printk(KERN_INFO KBUILD_MODNAME ":"
-              DRIVER_DESC " " DRIVER_VERSION "\n");
-
-       /* Register with the usb */
-       retval = usb_register(&aten_driver);
-       if (retval)
-               usb_serial_deregister(&aten_serial_driver);
-
-       return retval;
-}
-
-static void __exit aten_exit(void)
-{
-       usb_deregister(&aten_driver);
-       usb_serial_deregister(&aten_serial_driver);
-}
-
-module_init(aten_init);
-module_exit(aten_exit);
-
-/* Module information */
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug, "Debug enabled or not");
index 0ab9d15f3439085c4d39bd2d1e5ecab694657a86..f5416af1e902a8a447dcffbbcb47d928deff4e3a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/fb.h>
 #include <linux/mutex.h>
+#include <linux/vmalloc.h>
 
 #include "udlfb.h"
 
index 22f93dd0ba034ac741dcba70642fbf5272957070..251220dc885140479590224f80a9c0abcb5ee54a 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/tcp.h>
 #include <linux/in.h>
index a10ed27acbc2028ad1cf683f2fa3bd0d121286d2..f43ca416e4a88c4f989a31495181f4a6d155227b 100644 (file)
@@ -344,7 +344,7 @@ static CHIP_INFO chip_info_table[]= {
 };
 
 static struct pci_device_id device_id_table[] __devinitdata = {
-{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (int)&chip_info_table[0]},
+{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long)&chip_info_table[0]},
 { 0, }
 };
 #endif
@@ -369,7 +369,7 @@ static int  device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 #ifdef CONFIG_PM
 static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
-static int viawget_suspend(struct pci_dev *pcid, u32 state);
+static int viawget_suspend(struct pci_dev *pcid, pm_message_t state);
 static int viawget_resume(struct pci_dev *pcid);
 struct notifier_block device_notifier = {
         notifier_call:  device_notify_reboot,
@@ -3941,7 +3941,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
         while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
             if(pci_dev_driver(pdev) == &device_driver) {
                 if (pci_get_drvdata(pdev))
-                    viawget_suspend(pdev, 3);
+                    viawget_suspend(pdev, PMSG_HIBERNATE);
             }
         }
     }
@@ -3949,7 +3949,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 }
 
 static int
-viawget_suspend(struct pci_dev *pcid, u32 state)
+viawget_suspend(struct pci_dev *pcid, pm_message_t state)
 {
     int power_status;   // to silence the compiler
 
@@ -3971,7 +3971,7 @@ viawget_suspend(struct pci_dev *pcid, u32 state)
     memset(pMgmt->abyCurrBSSID, 0, 6);
     pMgmt->eCurrState = WMAC_STATE_IDLE;
     pci_disable_device(pcid);
-    power_status = pci_set_power_state(pcid, state);
+    power_status = pci_set_power_state(pcid, pci_choose_state(pcid, state));
     spin_unlock_irq(&pDevice->lock);
     return 0;
 }
index a913efc69669a221d336006a35d5155000a6081a..40de151f27898a1e20b82f22d80ccbc9448be558 100644 (file)
 #include <linux/fs.h>          /* everything... */
 #include <linux/errno.h>       /* error codes */
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
index b52cc830c0b49c90ba097bdeadfc4140d9c29d8f..f3873f650bb43f7f68f79ee87a8c8cdf13784b3a 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/phonedev.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
index 3f1045993474ce9ea9474920b870d6d75f6a1a15..e1f89416ef8cdf6235b2cfcebdbda23ab213f7e7 100644 (file)
@@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long _acm)
        struct acm_ru *rcv;
        unsigned long flags;
        unsigned char throttled;
+       struct usb_host_endpoint *ep;
 
        dbg("Entering acm_rx_tasklet");
 
@@ -462,11 +463,20 @@ urbs:
 
                rcv->buffer = buf;
 
-               usb_fill_bulk_urb(rcv->urb, acm->dev,
-                                 acm->rx_endpoint,
-                                 buf->base,
-                                 acm->readsize,
-                                 acm_read_bulk, rcv);
+               ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
+                               [usb_pipeendpoint(acm->rx_endpoint)];
+               if (usb_endpoint_xfer_int(&ep->desc))
+                       usb_fill_int_urb(rcv->urb, acm->dev,
+                                        acm->rx_endpoint,
+                                        buf->base,
+                                        acm->readsize,
+                                        acm_read_bulk, rcv, ep->desc.bInterval);
+               else
+                       usb_fill_bulk_urb(rcv->urb, acm->dev,
+                                         acm->rx_endpoint,
+                                         buf->base,
+                                         acm->readsize,
+                                         acm_read_bulk, rcv);
                rcv->urb->transfer_dma = buf->dma;
                rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -740,7 +750,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
        if (!ACM_READY(acm))
-               return -EINVAL;
+               return 0;
        /*
         * This is inaccurate (overcounts), but it works.
         */
@@ -1227,9 +1237,14 @@ made_compressed_probe:
                        goto alloc_fail7;
                }
 
-               usb_fill_bulk_urb(snd->urb, usb_dev,
-                       usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
-                       NULL, acm->writesize, acm_write_bulk, snd);
+               if (usb_endpoint_xfer_int(epwrite))
+                       usb_fill_int_urb(snd->urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+                               NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
+               else
+                       usb_fill_bulk_urb(snd->urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+                               NULL, acm->writesize, acm_write_bulk, snd);
                snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                snd->instance = acm;
        }
index 0fe434505ac44d8d6d9c066738b36dacdd0c62ac..ba589d4ca8bcb9e8783cc47bce18cab3faaa8301 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
index 3703789d0d2af8a7459138adb5903c548e704425..b09a527f73411499e2ab712c0f4d1b6f7d2c1946 100644 (file)
@@ -751,7 +751,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
 {
        struct device *dev = &data->usb_dev->dev;
        char *buffer;
-       int rv;
+       int rv = 0;
 
        buffer = kmalloc(0x18, GFP_KERNEL);
        if (!buffer)
@@ -763,7 +763,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
                             0, 0, buffer, 0x18, USBTMC_TIMEOUT);
        if (rv < 0) {
                dev_err(dev, "usb_control_msg returned %d\n", rv);
-               return rv;
+               goto err_out;
        }
 
        dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
@@ -773,7 +773,8 @@ static int get_capabilities(struct usbtmc_device_data *data)
        dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
        if (buffer[0] != USBTMC_STATUS_SUCCESS) {
                dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
-               return -EPERM;
+               rv = -EPERM;
+               goto err_out;
        }
 
        data->capabilities.interface_capabilities = buffer[4];
@@ -781,8 +782,9 @@ static int get_capabilities(struct usbtmc_device_data *data)
        data->capabilities.usb488_interface_capabilities = buffer[14];
        data->capabilities.usb488_device_capabilities = buffer[15];
 
+err_out:
        kfree(buffer);
-       return 0;
+       return rv;
 }
 
 #define capability_attribute(name)                                     \
index 69280c35b5cbc6d93cc50c99d7f4a7f747c1fc99..ad925946f869ea1ed435851b1efebd0cf7d200b4 100644 (file)
@@ -28,7 +28,7 @@ comment "Miscellaneous USB options"
        depends on USB
 
 config USB_DEVICEFS
-       bool "USB device filesystem (DEPRECATED)" if EMBEDDED
+       bool "USB device filesystem (DEPRECATED)"
        depends on USB
        ---help---
          If you say Y here (and to "/proc file system support" in the "File
index 24dfb33f90cb0fbc2268572ee0ed90ecc15efbb5..a16c538d0132958ab330b6993267663d45d4c4ef 100644 (file)
@@ -80,38 +80,18 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
        int max_tx;
        int i;
 
-       /* Allocate space for the SS endpoint companion descriptor */
-       ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
-                       GFP_KERNEL);
-       if (!ep->ss_ep_comp)
-               return -ENOMEM;
        desc = (struct usb_ss_ep_comp_descriptor *) buffer;
        if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
                dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
                                " interface %d altsetting %d ep %d: "
                                "using minimum values\n",
                                cfgno, inum, asnum, ep->desc.bEndpointAddress);
-               ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
-               ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
-               ep->ss_ep_comp->desc.bMaxBurst = 0;
-               /*
-                * Leave bmAttributes as zero, which will mean no streams for
-                * bulk, and isoc won't support multiple bursts of packets.
-                * With bursts of only one packet, and a Mult of 1, the max
-                * amount of data moved per endpoint service interval is one
-                * packet.
-                */
-               if (usb_endpoint_xfer_isoc(&ep->desc) ||
-                               usb_endpoint_xfer_int(&ep->desc))
-                       ep->ss_ep_comp->desc.wBytesPerInterval =
-                               ep->desc.wMaxPacketSize;
                /*
                 * The next descriptor is for an Endpoint or Interface,
                 * no extra descriptors to copy into the companion structure,
                 * and we didn't eat up any of the buffer.
                 */
-               retval = 0;
-               goto valid;
+               return 0;
        }
        memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
        desc = &ep->ss_ep_comp->desc;
@@ -320,6 +300,28 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                buffer += i;
                size -= i;
 
+               /* Allocate space for the SS endpoint companion descriptor */
+               endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
+                               GFP_KERNEL);
+               if (!endpoint->ss_ep_comp)
+                       return -ENOMEM;
+
+               /* Fill in some default values (may be overwritten later) */
+               endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
+               endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
+               endpoint->ss_ep_comp->desc.bMaxBurst = 0;
+               /*
+                * Leave bmAttributes as zero, which will mean no streams for
+                * bulk, and isoc won't support multiple bursts of packets.
+                * With bursts of only one packet, and a Mult of 1, the max
+                * amount of data moved per endpoint service interval is one
+                * packet.
+                */
+               if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
+                               usb_endpoint_xfer_int(&endpoint->desc))
+                       endpoint->ss_ep_comp->desc.wBytesPerInterval =
+                               endpoint->desc.wMaxPacketSize;
+
                if (size > 0) {
                        retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
                                        inum, asnum, endpoint, num_ep, buffer,
@@ -329,6 +331,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                                retval = buffer - buffer0;
                        }
                } else {
+                       dev_warn(ddev, "config %d interface %d altsetting %d "
+                               "endpoint 0x%X has no "
+                               "SuperSpeed companion descriptor\n",
+                               cfgno, inum, asnum, d->bEndpointAddress);
                        retval = buffer - buffer0;
                }
        } else {
index 73c108d117b4b3da95587c5366a4498a695a8e74..96f11715cd269b4cb8594c12c4c027ae50350af8 100644 (file)
@@ -136,17 +136,19 @@ static const struct class_info clas_info[] =
        {USB_CLASS_AUDIO,               "audio"},
        {USB_CLASS_COMM,                "comm."},
        {USB_CLASS_HID,                 "HID"},
-       {USB_CLASS_HUB,                 "hub"},
        {USB_CLASS_PHYSICAL,            "PID"},
+       {USB_CLASS_STILL_IMAGE,         "still"},
        {USB_CLASS_PRINTER,             "print"},
        {USB_CLASS_MASS_STORAGE,        "stor."},
+       {USB_CLASS_HUB,                 "hub"},
        {USB_CLASS_CDC_DATA,            "data"},
-       {USB_CLASS_APP_SPEC,            "app."},
-       {USB_CLASS_VENDOR_SPEC,         "vend."},
-       {USB_CLASS_STILL_IMAGE,         "still"},
        {USB_CLASS_CSCID,               "scard"},
        {USB_CLASS_CONTENT_SEC,         "c-sec"},
        {USB_CLASS_VIDEO,               "video"},
+       {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"},
+       {USB_CLASS_MISC,                "misc"},
+       {USB_CLASS_APP_SPEC,            "app."},
+       {USB_CLASS_VENDOR_SPEC,         "vend."},
        {-1,                            "unk."}         /* leave as last */
 };
 
index 308609039c73e1bbf1252adee9f2e276cc73c852..38b8bce782d6d12cbcb01a8b83452948e48570f7 100644 (file)
@@ -325,21 +325,34 @@ static void async_completed(struct urb *urb)
        struct async *as = urb->context;
        struct dev_state *ps = as->ps;
        struct siginfo sinfo;
+       struct pid *pid = NULL;
+       uid_t uid = 0;
+       uid_t euid = 0;
+       u32 secid = 0;
+       int signr;
 
        spin_lock(&ps->lock);
        list_move_tail(&as->asynclist, &ps->async_completed);
-       spin_unlock(&ps->lock);
        as->status = urb->status;
-       if (as->signr) {
+       signr = as->signr;
+       if (signr) {
                sinfo.si_signo = as->signr;
                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,
-                                     as->euid, as->secid);
+               pid = as->pid;
+               uid = as->uid;
+               euid = as->euid;
+               secid = as->secid;
        }
        snoop(&urb->dev->dev, "urb complete\n");
        snoop_urb(urb, as->userurb);
+       spin_unlock(&ps->lock);
+
+       if (signr)
+               kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
+                                     euid, secid);
+
        wake_up(&ps->wait);
 }
 
@@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                                USBDEVFS_URB_ZERO_PACKET |
                                USBDEVFS_URB_NO_INTERRUPT))
                return -EINVAL;
-       if (!uurb->buffer)
+       if (uurb->buffer_length > 0 && !uurb->buffer)
                return -EINVAL;
        if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
            (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
@@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        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",
@@ -1062,9 +1070,6 @@ 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(is_in ? VERIFY_WRITE : VERIFY_READ,
-                               uurb->buffer, uurb->buffer_length))
-                       return -EFAULT;
                snoop(&ps->dev->dev, "bulk urb\n");
                break;
 
@@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        return -EINVAL;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
-                               uurb->buffer, uurb->buffer_length))
-                       return -EFAULT;
                snoop(&ps->dev->dev, "interrupt urb\n");
                break;
 
        default:
                return -EINVAL;
        }
-       as = alloc_async(uurb->number_of_packets);
-       if (!as) {
+       if (uurb->buffer_length > 0 &&
+                       !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length)) {
                kfree(isopkt);
                kfree(dr);
-               return -ENOMEM;
+               return -EFAULT;
        }
-       as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL);
-       if (!as->urb->transfer_buffer) {
+       as = alloc_async(uurb->number_of_packets);
+       if (!as) {
                kfree(isopkt);
                kfree(dr);
-               free_async(as);
                return -ENOMEM;
        }
+       if (uurb->buffer_length > 0) {
+               as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
+                               GFP_KERNEL);
+               if (!as->urb->transfer_buffer) {
+                       kfree(isopkt);
+                       kfree(dr);
+                       free_async(as);
+                       return -ENOMEM;
+               }
+       }
        as->urb->dev = ps->dev;
        as->urb->pipe = (uurb->type << 30) |
                        __create_pipe(ps->dev, uurb->endpoint & 0xf) |
@@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        kfree(isopkt);
        as->ps = ps;
        as->userurb = arg;
-       if (uurb->endpoint & USB_DIR_IN)
+       if (is_in && uurb->buffer_length > 0)
                as->userbuffer = uurb->buffer;
        else
                as->userbuffer = NULL;
@@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        as->uid = cred->uid;
        as->euid = cred->euid;
        security_task_getsecid(current, &as->secid);
-       if (!is_in) {
+       if (!is_in && uurb->buffer_length > 0) {
                if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
-                               as->urb->transfer_buffer_length)) {
+                               uurb->buffer_length)) {
                        free_async(as);
                        return -EFAULT;
                }
@@ -1231,22 +1243,22 @@ 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;
+                       goto err_out;
        if (put_user(as->status, &userurb->status))
-               return -EFAULT;
+               goto err_out;
        if (put_user(urb->actual_length, &userurb->actual_length))
-               return -EFAULT;
+               goto err_out;
        if (put_user(urb->error_count, &userurb->error_count))
-               return -EFAULT;
+               goto err_out;
 
        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))
-                               return -EFAULT;
+                               goto err_out;
                        if (put_user(urb->iso_frame_desc[i].status,
                                     &userurb->iso_frame_desc[i].status))
-                               return -EFAULT;
+                               goto err_out;
                }
        }
 
@@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg)
        if (put_user(addr, (void __user * __user *)arg))
                return -EFAULT;
        return 0;
+
+err_out:
+       free_async(as);
+       return -EFAULT;
 }
 
 static struct async *reap_as(struct dev_state *ps)
index d397ecfd5b178d881f97c72e51989bfccbe2a064..ec5c67ea07b745a95b92e8db88349abadc1bbca1 100644 (file)
@@ -227,6 +227,10 @@ struct hc_driver {
                /* has a port been handed over to a companion? */
        int     (*port_handed_over)(struct usb_hcd *, int);
 
+               /* CLEAR_TT_BUFFER completion callback */
+       void    (*clear_tt_buffer_complete)(struct usb_hcd *,
+                               struct usb_host_endpoint *);
+
        /* xHCI specific functions */
                /* Called by usb_alloc_dev to alloc HC device structures */
        int     (*alloc_dev)(struct usb_hcd *, struct usb_device *);
index 2af3b4f0605405dd723b1ccd4f853f7f85dc1848..71f86c60d83c3962cf8b7eabe1d709d2d87b7a76 100644 (file)
@@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
  * talking to TTs must queue control transfers (not just bulk and iso), so
  * both can talk to the same hub concurrently.
  */
-static void hub_tt_kevent (struct work_struct *work)
+static void hub_tt_work(struct work_struct *work)
 {
        struct usb_hub          *hub =
-               container_of(work, struct usb_hub, tt.kevent);
+               container_of(work, struct usb_hub, tt.clear_work);
        unsigned long           flags;
        int                     limit = 100;
 
@@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work)
                struct list_head        *next;
                struct usb_tt_clear     *clear;
                struct usb_device       *hdev = hub->hdev;
+               const struct hc_driver  *drv;
                int                     status;
 
                next = hub->tt.clear_list.next;
@@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work)
                /* drop lock so HCD can concurrently report other TT errors */
                spin_unlock_irqrestore (&hub->tt.lock, flags);
                status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
-               spin_lock_irqsave (&hub->tt.lock, flags);
-
                if (status)
                        dev_err (&hdev->dev,
                                "clear tt %d (%04x) error %d\n",
                                clear->tt, clear->devinfo, status);
+
+               /* Tell the HCD, even if the operation failed */
+               drv = clear->hcd->driver;
+               if (drv->clear_tt_buffer_complete)
+                       (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep);
+
                kfree(clear);
+               spin_lock_irqsave(&hub->tt.lock, flags);
        }
        spin_unlock_irqrestore (&hub->tt.lock, flags);
 }
 
 /**
- * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
- * @udev: the device whose split transaction failed
- * @pipe: identifies the endpoint of the failed transaction
+ * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
+ * @urb: an URB associated with the failed or incomplete split transaction
  *
  * High speed HCDs use this to tell the hub driver that some split control or
  * bulk transaction failed in a way that requires clearing internal state of
@@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work)
  * It may not be possible for that hub to handle additional full (or low)
  * speed transactions until that state is fully cleared out.
  */
-void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
+int usb_hub_clear_tt_buffer(struct urb *urb)
 {
+       struct usb_device       *udev = urb->dev;
+       int                     pipe = urb->pipe;
        struct usb_tt           *tt = udev->tt;
        unsigned long           flags;
        struct usb_tt_clear     *clear;
@@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
        if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {
                dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
                /* FIXME recover somehow ... RESET_TT? */
-               return;
+               return -ENOMEM;
        }
 
        /* info that CLEAR_TT_BUFFER needs */
@@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
                        : (USB_ENDPOINT_XFER_BULK << 11);
        if (usb_pipein (pipe))
                clear->devinfo |= 1 << 15;
-       
+
+       /* info for completion callback */
+       clear->hcd = bus_to_hcd(udev->bus);
+       clear->ep = urb->ep;
+
        /* tell keventd to clear state for this TT */
        spin_lock_irqsave (&tt->lock, flags);
        list_add_tail (&clear->clear_list, &tt->clear_list);
-       schedule_work (&tt->kevent);
+       schedule_work(&tt->clear_work);
        spin_unlock_irqrestore (&tt->lock, flags);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
+EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
 
 /* If do_delay is false, return the number of milliseconds the caller
  * needs to delay.
@@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        if (hub->has_indicators)
                cancel_delayed_work_sync(&hub->leds);
        if (hub->tt.hub)
-               cancel_work_sync(&hub->tt.kevent);
+               cancel_work_sync(&hub->tt.clear_work);
 }
 
 /* caller has locked the hub device */
@@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub,
 
        spin_lock_init (&hub->tt.lock);
        INIT_LIST_HEAD (&hub->tt.clear_list);
-       INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
+       INIT_WORK(&hub->tt.clear_work, hub_tt_work);
        switch (hdev->descriptor.bDeviceProtocol) {
                case 0:
                        break;
index 889c0f32a40b729431f2dab51d13aead39f5f3e8..de8081f065edda76ae95a415b98c6db86a0d9a57 100644 (file)
@@ -188,16 +188,18 @@ struct usb_tt {
        /* for control/bulk error recovery (CLEAR_TT_BUFFER) */
        spinlock_t              lock;
        struct list_head        clear_list;     /* of usb_tt_clear */
-       struct work_struct                      kevent;
+       struct work_struct      clear_work;
 };
 
 struct usb_tt_clear {
        struct list_head        clear_list;
        unsigned                tt;
        u16                     devinfo;
+       struct usb_hcd          *hcd;
+       struct usb_host_endpoint        *ep;
 };
 
-extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
+extern int usb_hub_clear_tt_buffer(struct urb *urb);
 extern void usb_ep0_reinit(struct usb_device *);
 
 #endif /* __LINUX_HUB_H */
index 2bed83caacb1a0c714a2e05af21242bbb504dcad..9720e699f4729737cbdd90946f234e567fc0d874 100644 (file)
@@ -806,6 +806,48 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
        return rc;
 }
 
+static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
+{
+       int err;
+
+       if (dev->have_langid)
+               return 0;
+
+       if (dev->string_langid < 0)
+               return -EPIPE;
+
+       err = usb_string_sub(dev, 0, 0, tbuf);
+
+       /* If the string was reported but is malformed, default to english
+        * (0x0409) */
+       if (err == -ENODATA || (err > 0 && err < 4)) {
+               dev->string_langid = 0x0409;
+               dev->have_langid = 1;
+               dev_err(&dev->dev,
+                       "string descriptor 0 malformed (err = %d), "
+                       "defaulting to 0x%04x\n",
+                               err, dev->string_langid);
+               return 0;
+       }
+
+       /* In case of all other errors, we assume the device is not able to
+        * deal with strings at all. Set string_langid to -1 in order to
+        * prevent any string to be retrieved from the device */
+       if (err < 0) {
+               dev_err(&dev->dev, "string descriptor 0 read error: %d\n",
+                                       err);
+               dev->string_langid = -1;
+               return -EPIPE;
+       }
+
+       /* always use the first langid listed */
+       dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+       dev->have_langid = 1;
+       dev_dbg(&dev->dev, "default language 0x%04x\n",
+                               dev->string_langid);
+       return 0;
+}
+
 /**
  * usb_string - returns UTF-8 version of a string descriptor
  * @dev: the device whose string descriptor is being retrieved
@@ -837,24 +879,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
        if (!tbuf)
                return -ENOMEM;
 
-       /* get langid for strings if it's not yet known */
-       if (!dev->have_langid) {
-               err = usb_string_sub(dev, 0, 0, tbuf);
-               if (err < 0) {
-                       dev_err(&dev->dev,
-                               "string descriptor 0 read error: %d\n",
-                               err);
-               } else if (err < 4) {
-                       dev_err(&dev->dev, "string descriptor 0 too short\n");
-               } else {
-                       dev->string_langid = tbuf[2] | (tbuf[3] << 8);
-                       /* always use the first langid listed */
-                       dev_dbg(&dev->dev, "default language 0x%04x\n",
-                               dev->string_langid);
-               }
-
-               dev->have_langid = 1;
-       }
+       err = usb_get_langid(dev, tbuf);
+       if (err < 0)
+               goto errout;
 
        err = usb_string_sub(dev, dev->string_langid, index, tbuf);
        if (err < 0)
index 5d1ddf485d1eb6d5d55e12a4eca7536e10a75838..7f8e83a954ac6881861bdc0d2e334ea85944db7a 100644 (file)
@@ -286,6 +286,27 @@ config USB_S3C_HSOTG
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_IMX
+       boolean "Freescale IMX USB Peripheral Controller"
+       depends on ARCH_MX1
+       help
+          Freescale's IMX series include an integrated full speed
+          USB 1.1 device controller.  The controller in the IMX series
+          is register-compatible.
+
+          It has Six fixed-function endpoints, as well as endpoint
+          zero (for control transfers).
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "imx_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_IMX
+       tristate
+       depends on USB_GADGET_IMX
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_S3C2410
        boolean "S3C2410 USB Device Controller"
        depends on ARCH_S3C2410
@@ -321,27 +342,6 @@ config USB_GADGET_MUSB_HDRC
          This OTG-capable silicon IP is used in dual designs including
          the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
-config USB_GADGET_IMX
-       boolean "Freescale IMX USB Peripheral Controller"
-       depends on ARCH_MX1
-       help
-          Freescale's IMX series include an integrated full speed
-          USB 1.1 device controller.  The controller in the IMX series
-          is register-compatible.
-
-          It has Six fixed-function endpoints, as well as endpoint
-          zero (for control transfers).
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "imx_udc" and force all
-          gadget drivers to also be dynamically linked.
-
-config USB_IMX
-       tristate
-       depends on USB_GADGET_IMX
-       default USB_GADGET
-       select USB_GADGET_SELECTED
-
 config USB_GADGET_M66592
        boolean "Renesas M66592 USB Peripheral Controller"
        select USB_GADGET_DUALSPEED
@@ -604,6 +604,7 @@ config USB_ZERO_HNPTEST
 config USB_AUDIO
        tristate "Audio Gadget (EXPERIMENTAL)"
        depends on SND
+       select SND_PCM
        help
          Gadget Audio is compatible with USB Audio Class specification 1.0.
          It will include at least one AudioControl interface, zero or more
index 826f3adde5d8a4ac0df29265d88cadd1ab541d05..77352ccc245e0ab3a456b22ce0ed6a8b2f7e411b 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 94de7e864614961f322412d2855289041fdda22e..9f80f4e970bd00693cf3140483940eb46843cdef 100644 (file)
@@ -42,9 +42,9 @@
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
 
-/* Thanks to NetChip Technologies for donating this product ID. */
-#define AUDIO_VENDOR_NUM               0x0525  /* NetChip */
-#define AUDIO_PRODUCT_NUM              0xa4a1  /* Linux-USB Audio Gadget */
+/* Thanks to Linux Foundation for donating this product ID. */
+#define AUDIO_VENDOR_NUM               0x1d6b  /* Linux Foundation */
+#define AUDIO_PRODUCT_NUM              0x0101  /* Linux-USB Audio Gadget */
 
 /*-------------------------------------------------------------------------*/
 
index d006dc652e025558e3157691b0f855b43452a6ad..bd102f5052ba67453c3a2dd30a2eefde46ce59ee 100644 (file)
@@ -293,15 +293,16 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
                /* CDC Subset */
                eth_config_driver.label = "CDC Subset/SAFE";
 
-               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM),
-               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM),
-               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM);
+               if (!has_rndis())
+                       device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
        }
 
        if (has_rndis()) {
                /* RNDIS plus ECM-or-Subset */
-               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM),
-               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM),
+               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
                device_desc.bNumConfigurations = 2;
        }
 
index 6829d5961359278745a63d0f3ef73cb68c5164ab..a3913519fd5841cefc0718639af38b2bbf62ae40 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 0ce4e2819847c13fb7548fcf910923495d4588ba..ed21e263f832f05d977aa4c4acd41881dd013002 100644 (file)
@@ -139,7 +139,7 @@ static int is_vbus_present(void)
 {
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
 
-       if (mach->gpio_vbus) {
+       if (gpio_is_valid(mach->gpio_vbus)) {
                int value = gpio_get_value(mach->gpio_vbus);
 
                if (mach->gpio_vbus_inverted)
@@ -158,7 +158,7 @@ static void pullup_off(void)
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
        int off_level = mach->gpio_pullup_inverted;
 
-       if (mach->gpio_pullup)
+       if (gpio_is_valid(mach->gpio_pullup))
                gpio_set_value(mach->gpio_pullup, off_level);
        else if (mach->udc_command)
                mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
@@ -169,7 +169,7 @@ static void pullup_on(void)
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
        int on_level = !mach->gpio_pullup_inverted;
 
-       if (mach->gpio_pullup)
+       if (gpio_is_valid(mach->gpio_pullup))
                gpio_set_value(mach->gpio_pullup, on_level);
        else if (mach->udc_command)
                mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
@@ -1000,7 +1000,7 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
        udc = container_of(_gadget, struct pxa25x_udc, gadget);
 
        /* not all boards support pullup control */
-       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+       if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
                return -EOPNOTSUPP;
 
        udc->pullup = (is_active != 0);
@@ -1802,11 +1802,13 @@ pxa25x_udc_irq(int irq, void *_dev)
                                        USIR0 |= tmp;
                                        handled = 1;
                                }
+#ifndef        CONFIG_USB_PXA25X_SMALL
                                if (usir1 & tmp) {
                                        handle_ep(&dev->ep[i+8]);
                                        USIR1 |= tmp;
                                        handled = 1;
                                }
+#endif
                        }
                }
 
@@ -2160,7 +2162,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        dev->dev = &pdev->dev;
        dev->mach = pdev->dev.platform_data;
 
-       if (dev->mach->gpio_vbus) {
+       if (gpio_is_valid(dev->mach->gpio_vbus)) {
                if ((retval = gpio_request(dev->mach->gpio_vbus,
                                "pxa25x_udc GPIO VBUS"))) {
                        dev_dbg(&pdev->dev,
@@ -2173,7 +2175,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        } else
                vbus_irq = 0;
 
-       if (dev->mach->gpio_pullup) {
+       if (gpio_is_valid(dev->mach->gpio_pullup)) {
                if ((retval = gpio_request(dev->mach->gpio_pullup,
                                "pca25x_udc GPIO PULLUP"))) {
                        dev_dbg(&pdev->dev,
@@ -2256,10 +2258,10 @@ lubbock_fail0:
 #endif
        free_irq(irq, dev);
  err_irq1:
-       if (dev->mach->gpio_pullup)
+       if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
-       if (dev->mach->gpio_vbus)
+       if (gpio_is_valid(dev->mach->gpio_vbus))
                gpio_free(dev->mach->gpio_vbus);
  err_gpio_vbus:
        clk_put(dev->clk);
@@ -2294,11 +2296,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
                free_irq(LUBBOCK_USB_IRQ, dev);
        }
 #endif
-       if (dev->mach->gpio_vbus) {
+       if (gpio_is_valid(dev->mach->gpio_vbus)) {
                free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
                gpio_free(dev->mach->gpio_vbus);
        }
-       if (dev->mach->gpio_pullup)
+       if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
 
        clk_put(dev->clk);
@@ -2329,7 +2331,7 @@ static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state)
        struct pxa25x_udc       *udc = platform_get_drvdata(dev);
        unsigned long flags;
 
-       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+       if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
                WARNING("USB host won't detect disconnect!\n");
        udc->suspended = 1;
 
index 2b4660e08c4db367af0e6c5159855b675616eb9a..ca41b0b5afb352233e86c5ccbd45dace08f4431a 100644 (file)
@@ -442,6 +442,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
        case OID_802_3_MAC_OPTIONS:
                pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
                break;
 
        /* ieee802.3 statistics OIDs (table 4-4) */
index 9a2b8920532d0ad0fa248a7ca073051d55be8405..a9b452fe622195ad832acdc78fba40759218f820 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 0c03471f0d4197f718bf49aa95f315ba0ada5771..1a920c70b5a150f0a2670f8d170d579c582544ac 100644 (file)
@@ -181,26 +181,27 @@ config USB_OHCI_HCD_PPC_SOC
          Enables support for the USB controller on the MPC52xx or
          STB03xxx processor chip.  If unsure, say Y.
 
-config USB_OHCI_HCD_PPC_OF
-       bool "OHCI support for PPC USB controller on OF platform bus"
-       depends on USB_OHCI_HCD && PPC_OF
-       default y
-       ---help---
-         Enables support for the USB controller PowerPC present on the
-         OpenFirmware platform bus.
-
 config USB_OHCI_HCD_PPC_OF_BE
-       bool "Support big endian HC"
-       depends on USB_OHCI_HCD_PPC_OF
-       default y
+       bool "OHCI support for OF platform bus (big endian)"
+       depends on USB_OHCI_HCD && PPC_OF
        select USB_OHCI_BIG_ENDIAN_DESC
        select USB_OHCI_BIG_ENDIAN_MMIO
+       ---help---
+         Enables support for big-endian USB controllers present on the
+         OpenFirmware platform bus.
 
 config USB_OHCI_HCD_PPC_OF_LE
-       bool "Support little endian HC"
-       depends on USB_OHCI_HCD_PPC_OF
-       default n
+       bool "OHCI support for OF platform bus (little endian)"
+       depends on USB_OHCI_HCD && PPC_OF
        select USB_OHCI_LITTLE_ENDIAN
+       ---help---
+         Enables support for little-endian USB controllers present on the
+         OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF
+       bool
+       depends on USB_OHCI_HCD && PPC_OF
+       default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
 
 config USB_OHCI_HCD_PCI
        bool "OHCI support for PCI-bus USB controllers"
index c3a778bd359c9b883bd6e361e78951818fd3a280..59d208d94d4e772d5b1a8cc6f8a009d94132625f 100644 (file)
@@ -113,6 +113,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
        .bus_resume             = ehci_bus_resume,
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
index bf86809c5120795eac8521b68e2159d2fef37127..991174937db31ed5d829d6e1fdc0b3ea024e47bd 100644 (file)
@@ -325,6 +325,8 @@ static const struct hc_driver ehci_fsl_hc_driver = {
        .bus_resume = ehci_bus_resume,
        .relinquish_port = ehci_relinquish_port,
        .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 };
 
 static int ehci_fsl_drv_probe(struct platform_device *pdev)
index 2b72473544d31d798034ed5aa92cb555384a8055..7d03549c3339ecc5ebdc5025db1d9f3b6d42f148 100644 (file)
@@ -1003,6 +1003,8 @@ idle_timeout:
                schedule_timeout_uninterruptible(1);
                goto rescan;
        case QH_STATE_IDLE:             /* fully unlinked */
+               if (qh->clearing_tt)
+                       goto idle_timeout;
                if (list_empty (&qh->qtd_list)) {
                        qh_put (qh);
                        break;
@@ -1030,12 +1032,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct ehci_qh          *qh;
        int                     eptype = usb_endpoint_type(&ep->desc);
+       int                     epnum = usb_endpoint_num(&ep->desc);
+       int                     is_out = usb_endpoint_dir_out(&ep->desc);
+       unsigned long           flags;
 
        if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
                return;
 
- rescan:
-       spin_lock_irq(&ehci->lock);
+       spin_lock_irqsave(&ehci->lock, flags);
        qh = ep->hcpriv;
 
        /* For Bulk and Interrupt endpoints we maintain the toggle state
@@ -1044,29 +1048,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
         * the toggle bit in the QH.
         */
        if (qh) {
+               usb_settoggle(qh->dev, epnum, is_out, 0);
                if (!list_empty(&qh->qtd_list)) {
                        WARN_ONCE(1, "clear_halt for a busy endpoint\n");
-               } else if (qh->qh_state == QH_STATE_IDLE) {
-                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
-               } else {
-                       /* It's not safe to write into the overlay area
-                        * while the QH is active.  Unlink it first and
-                        * wait for the unlink to complete.
+               } else if (qh->qh_state == QH_STATE_LINKED) {
+
+                       /* The toggle value in the QH can't be updated
+                        * while the QH is active.  Unlink it now;
+                        * re-linking will call qh_refresh().
                         */
-                       if (qh->qh_state == QH_STATE_LINKED) {
-                               if (eptype == USB_ENDPOINT_XFER_BULK) {
-                                       unlink_async(ehci, qh);
-                               } else {
-                                       intr_deschedule(ehci, qh);
-                                       (void) qh_schedule(ehci, qh);
-                               }
+                       if (eptype == USB_ENDPOINT_XFER_BULK) {
+                               unlink_async(ehci, qh);
+                       } else {
+                               intr_deschedule(ehci, qh);
+                               (void) qh_schedule(ehci, qh);
                        }
-                       spin_unlock_irq(&ehci->lock);
-                       schedule_timeout_uninterruptible(1);
-                       goto rescan;
                }
        }
-       spin_unlock_irq(&ehci->lock);
+       spin_unlock_irqrestore(&ehci->lock, flags);
 }
 
 static int ehci_get_frame (struct usb_hcd *hcd)
index a44bb4a949543d797f336827edb8ac6fa088d8ac..89b7c70c6ed6f015077a6a0233b78b080f581043 100644 (file)
@@ -61,6 +61,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int ixp4xx_ehci_probe(struct platform_device *pdev)
index 770dd9aba62a9f07aabd9863e59fc4acae6a81dd..1d283e1b2b8de543e56f4e695e333383ee5d116d 100644 (file)
@@ -105,6 +105,7 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        int retval;
 
+       ehci_reset(ehci);
        retval = ehci_halt(ehci);
        if (retval)
                return retval;
@@ -118,7 +119,6 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
 
        hcd->has_tt = 1;
 
-       ehci_reset(ehci);
        ehci_port_power(ehci, 0);
 
        return retval;
@@ -165,6 +165,8 @@ static const struct hc_driver ehci_orion_hc_driver = {
        .bus_resume = ehci_bus_resume,
        .relinquish_port = ehci_relinquish_port,
        .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 };
 
 static void __init
index f3683e1da16134b3c20a6239b5edfd406af923aa..c2f1b7df918cd52ddd62385e3f02f5696d7f6f06 100644 (file)
@@ -404,6 +404,8 @@ static const struct hc_driver ehci_pci_hc_driver = {
        .bus_resume =           ehci_bus_resume,
        .relinquish_port =      ehci_relinquish_port,
        .port_handed_over =     ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 /*-------------------------------------------------------------------------*/
index fbd272288fc2cf799ef1d075adea282dd01aa863..36f96da129f5c637208031ec04913be3f0cc6e67 100644 (file)
@@ -79,6 +79,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 
index 93f7035d00a16ad1da984e9f1b81c521afa79cba..1dee33b9139e65d1f8714234c7ecde9e7b3d0d24 100644 (file)
@@ -75,6 +75,8 @@ static const struct hc_driver ps3_ehci_hc_driver = {
 #endif
        .relinquish_port        = ehci_relinquish_port,
        .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
 static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev)
index 3192f683f8073293a6366b532ced3ff0dd5007f1..9a1384747f3bc8ca092b226d6de8fed5d6850276 100644 (file)
@@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
        qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
        qh->hw_alt_next = EHCI_LIST_END(ehci);
 
+       /* Except for control endpoints, we make hardware maintain data
+        * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+        * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+        * ever clear it.
+        */
+       if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+               unsigned        is_out, epnum;
+
+               is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+               epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
+               if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+                       usb_settoggle (qh->dev, epnum, is_out, 1);
+               }
+       }
+
        /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
        wmb ();
        qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
@@ -123,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 /*-------------------------------------------------------------------------*/
 
+static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       struct ehci_qh          *qh = ep->hcpriv;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&ehci->lock, flags);
+       qh->clearing_tt = 0;
+       if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
+                       && HC_IS_RUNNING(hcd->state))
+               qh_link_async(ehci, qh);
+       spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
+               struct urb *urb, u32 token)
+{
+
+       /* If an async split transaction gets an error or is unlinked,
+        * the TT buffer may be left in an indeterminate state.  We
+        * have to clear the TT buffer.
+        *
+        * Note: this routine is never called for Isochronous transfers.
+        */
+       if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
+#ifdef DEBUG
+               struct usb_device *tt = urb->dev->tt->hub;
+               dev_dbg(&tt->dev,
+                       "clear tt buffer port %d, a%d ep%d t%08x\n",
+                       urb->dev->ttport, urb->dev->devnum,
+                       usb_pipeendpoint(urb->pipe), token);
+#endif /* DEBUG */
+               if (!ehci_is_TDI(ehci)
+                               || urb->dev->tt->hub !=
+                                  ehci_to_hcd(ehci)->self.root_hub) {
+                       if (usb_hub_clear_tt_buffer(urb) == 0)
+                               qh->clearing_tt = 1;
+               } else {
+
+                       /* REVISIT ARC-derived cores don't clear the root
+                        * hub TT buffer in this way...
+                        */
+               }
+       }
+}
+
 static int qtd_copy_status (
        struct ehci_hcd *ehci,
        struct urb *urb,
@@ -149,6 +214,14 @@ static int qtd_copy_status (
                if (token & QTD_STS_BABBLE) {
                        /* FIXME "must" disable babbling device's port too */
                        status = -EOVERFLOW;
+               /* CERR nonzero + halt --> stall */
+               } else if (QTD_CERR(token)) {
+                       status = -EPIPE;
+
+               /* In theory, more than one of the following bits can be set
+                * since they are sticky and the transaction is retried.
+                * Which to test first is rather arbitrary.
+                */
                } else if (token & QTD_STS_MMF) {
                        /* fs/ls interrupt xfer missed the complete-split */
                        status = -EPROTO;
@@ -157,21 +230,15 @@ static int qtd_copy_status (
                                ? -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))
-                               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");
-                               status = -EPROTO;
-                       }
-               /* CERR nonzero + no errors + halt --> stall */
-               } else if (QTD_CERR (token))
-                       status = -EPIPE;
-               else    /* unknown */
+                       /* timeout, bad CRC, wrong PID, etc */
+                       ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n",
+                               urb->dev->devpath,
+                               usb_pipeendpoint(urb->pipe),
+                               usb_pipein(urb->pipe) ? "in" : "out");
+                       status = -EPROTO;
+               } else {        /* unknown */
                        status = -EPROTO;
+               }
 
                ehci_vdbg (ehci,
                        "dev%d ep%d%s qtd token %08x --> status %d\n",
@@ -179,28 +246,6 @@ static int qtd_copy_status (
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
                        token, status);
-
-               /* if async CSPLIT failed, try cleaning out the TT buffer */
-               if (status != -EPIPE
-                               && urb->dev->tt
-                               && !usb_pipeint(urb->pipe)
-                               && ((token & QTD_STS_MMF) != 0
-                                       || QTD_CERR(token) == 0)
-                               && (!ehci_is_TDI(ehci)
-                                       || urb->dev->tt->hub !=
-                                          ehci_to_hcd(ehci)->self.root_hub)) {
-#ifdef DEBUG
-                       struct usb_device *tt = urb->dev->tt->hub;
-                       dev_dbg (&tt->dev,
-                               "clear tt buffer port %d, a%d ep%d t%08x\n",
-                               urb->dev->ttport, urb->dev->devnum,
-                               usb_pipeendpoint (urb->pipe), token);
-#endif /* DEBUG */
-                       /* REVISIT ARC-derived cores don't clear the root
-                        * hub TT buffer in this way...
-                        */
-                       usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
-               }
        }
 
        return status;
@@ -391,9 +436,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        /* qh unlinked; token in overlay may be most current */
                        if (state == QH_STATE_IDLE
                                        && cpu_to_hc32(ehci, qtd->qtd_dma)
-                                               == qh->hw_current)
+                                               == qh->hw_current) {
                                token = hc32_to_cpu(ehci, qh->hw_token);
 
+                               /* An unlink may leave an incomplete
+                                * async transaction in the TT buffer.
+                                * We have to clear it.
+                                */
+                               ehci_clear_tt_buffer(ehci, qh, urb, token);
+                       }
+
                        /* force halt for unlinked or blocked qh, so we'll
                         * patch the qh later and so that completions can't
                         * activate it while we "know" it's stopped.
@@ -419,6 +471,13 @@ halt:
                                        && (qtd->hw_alt_next
                                                & EHCI_LIST_END(ehci)))
                                last_status = -EINPROGRESS;
+
+                       /* As part of low/full-speed endpoint-halt processing
+                        * we must clear the TT buffer (11.17.5).
+                        */
+                       if (unlikely(last_status != -EINPROGRESS &&
+                                       last_status != -EREMOTEIO))
+                               ehci_clear_tt_buffer(ehci, qh, urb, token);
                }
 
                /* if we're removing something not at the queue head,
@@ -834,6 +893,7 @@ done:
        qh->qh_state = QH_STATE_IDLE;
        qh->hw_info1 = cpu_to_hc32(ehci, info1);
        qh->hw_info2 = cpu_to_hc32(ehci, info2);
+       usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
        qh_refresh (ehci, qh);
        return qh;
 }
@@ -847,6 +907,10 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        __hc32          dma = QH_NEXT(ehci, qh->qh_dma);
        struct ehci_qh  *head;
 
+       /* Don't link a QH if there's a Clear-TT-Buffer pending */
+       if (unlikely(qh->clearing_tt))
+               return;
+
        /* (re)start the async schedule? */
        head = ehci->async;
        timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -864,7 +928,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                }
        }
 
-       /* clear halt and maybe recover from silicon quirk */
+       /* clear halt and/or toggle; and maybe recover from silicon quirk */
        if (qh->qh_state == QH_STATE_IDLE)
                qh_refresh (ehci, qh);
 
index 9d1babc7ff6553c64de8cec32fcfcff3f5ce5967..74f7f83b29ad9485ec9242afdbc1f91115a98f76 100644 (file)
@@ -1619,11 +1619,14 @@ itd_complete (
                                desc->status = -EPROTO;
 
                        /* HC need not update length with this error */
-                       if (!(t & EHCI_ISOC_BABBLE))
-                               desc->actual_length = EHCI_ITD_LENGTH (t);
+                       if (!(t & EHCI_ISOC_BABBLE)) {
+                               desc->actual_length = EHCI_ITD_LENGTH(t);
+                               urb->actual_length += desc->actual_length;
+                       }
                } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
                        desc->status = 0;
-                       desc->actual_length = EHCI_ITD_LENGTH (t);
+                       desc->actual_length = EHCI_ITD_LENGTH(t);
+                       urb->actual_length += desc->actual_length;
                } else {
                        /* URB was too late */
                        desc->status = -EXDEV;
@@ -2014,7 +2017,8 @@ sitd_complete (
                        desc->status = -EPROTO;
        } else {
                desc->status = 0;
-               desc->actual_length = desc->length - SITD_LENGTH (t);
+               desc->actual_length = desc->length - SITD_LENGTH(t);
+               urb->actual_length += desc->actual_length;
        }
        stream->depth -= stream->interval << 3;
 
index 90ad3395bb21f0f96923ab21431dc7c44165badb..2bfff30f4704f7521678239df30c07323e0d3e59 100644 (file)
@@ -354,7 +354,9 @@ struct ehci_qh {
        unsigned short          period;         /* polling interval */
        unsigned short          start;          /* where polling starts */
 #define NO_FRAME ((unsigned short)~0)                  /* pick new start */
+
        struct usb_device       *dev;           /* access to TT */
+       unsigned                clearing_tt:1;  /* Clear-TT-Buf in progress */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
index bb63b68ddb7745486e841f3bdb73b011d1be12da..62a226b616707a2dcb0ba7667f537f4d8bb7481c 100644 (file)
@@ -576,9 +576,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
                        out_be16(&usb->fhci->regs->usb_event,
                                 usb->saved_msk);
                } else if (usb->port_status == FHCI_PORT_DISABLED) {
-                       if (fhci_ioports_check_bus_state(fhci) == 1 &&
-                                       usb->port_status != FHCI_PORT_LOW &&
-                                       usb->port_status != FHCI_PORT_FULL)
+                       if (fhci_ioports_check_bus_state(fhci) == 1)
                                fhci_device_connected_interrupt(fhci);
                }
                usb_er &= ~USB_E_RESET_MASK;
@@ -605,9 +603,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
        }
 
        if (usb_er & USB_E_IDLE_MASK) {
-               if (usb->port_status == FHCI_PORT_DISABLED &&
-                               usb->port_status != FHCI_PORT_LOW &&
-                               usb->port_status != FHCI_PORT_FULL) {
+               if (usb->port_status == FHCI_PORT_DISABLED) {
                        usb_er &= ~USB_E_RESET_MASK;
                        fhci_device_connected_interrupt(fhci);
                } else if (usb->port_status ==
index 3fa3a17027963af75a2d15d5c5da7990b7c5fc7f..d4feebfc63bd1b51088a9e22cc618db1eb0f092b 100644 (file)
@@ -361,7 +361,7 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev)
 
 static struct platform_driver isp1760_plat_driver = {
        .probe  = isp1760_plat_probe,
-       .remove = isp1760_plat_remove,
+       .remove = __devexit_p(isp1760_plat_remove),
        .driver = {
                .name   = "isp1760",
        },
index f3aaba35e912fba4e021e3a6fcf7dd1c22d1153f..83cbecd2a1ed7177029d8f52b7a512b959f9e2b1 100644 (file)
@@ -282,6 +282,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
 static void ohci_omap_stop(struct usb_hcd *hcd)
 {
        dev_dbg(hcd->self.controller, "stopping USB Controller\n");
+       ohci_stop(hcd);
        omap_ohci_clock_power(0);
 }
 
index 56976cc0352a9ae9e87a0a1cb681135410e0e581..e18f74946e6824a427bd5b3b0185ee79ffebcd35 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
index 2501c571f855263f21200265888d58602deac86f..705e34324156f069ce4d56f7e596732bbc2fcc93 100644 (file)
@@ -173,6 +173,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int
 {
        void *addr;
        u32 temp;
+       u64 temp_64;
 
        addr = &ir_set->irq_pending;
        temp = xhci_readl(xhci, addr);
@@ -200,25 +201,15 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int
                xhci_dbg(xhci, "  WARN: %p: ir_set.rsvd = 0x%x\n",
                                addr, (unsigned int)temp);
 
-       addr = &ir_set->erst_base[0];
-       temp = xhci_readl(xhci, addr);
-       xhci_dbg(xhci, "  %p: ir_set.erst_base[0] = 0x%x\n",
-                       addr, (unsigned int) temp);
-
-       addr = &ir_set->erst_base[1];
-       temp = xhci_readl(xhci, addr);
-       xhci_dbg(xhci, "  %p: ir_set.erst_base[1] = 0x%x\n",
-                       addr, (unsigned int) temp);
+       addr = &ir_set->erst_base;
+       temp_64 = xhci_read_64(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_base = @%08llx\n",
+                       addr, temp_64);
 
-       addr = &ir_set->erst_dequeue[0];
-       temp = xhci_readl(xhci, addr);
-       xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[0] = 0x%x\n",
-                       addr, (unsigned int) temp);
-
-       addr = &ir_set->erst_dequeue[1];
-       temp = xhci_readl(xhci, addr);
-       xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[1] = 0x%x\n",
-                       addr, (unsigned int) temp);
+       addr = &ir_set->erst_dequeue;
+       temp_64 = xhci_read_64(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_dequeue = @%08llx\n",
+                       addr, temp_64);
 }
 
 void xhci_print_run_regs(struct xhci_hcd *xhci)
@@ -268,8 +259,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
                xhci_dbg(xhci, "Link TRB:\n");
                xhci_print_trb_offsets(xhci, trb);
 
-               address = trb->link.segment_ptr[0] +
-                       (((u64) trb->link.segment_ptr[1]) << 32);
+               address = trb->link.segment_ptr;
                xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
 
                xhci_dbg(xhci, "Interrupter target = 0x%x\n",
@@ -282,8 +272,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
                                (unsigned int) (trb->link.control & TRB_NO_SNOOP));
                break;
        case TRB_TYPE(TRB_TRANSFER):
-               address = trb->trans_event.buffer[0] +
-                       (((u64) trb->trans_event.buffer[1]) << 32);
+               address = trb->trans_event.buffer;
                /*
                 * FIXME: look at flags to figure out if it's an address or if
                 * the data is directly in the buffer field.
@@ -291,8 +280,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
                xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
                break;
        case TRB_TYPE(TRB_COMPLETION):
-               address = trb->event_cmd.cmd_trb[0] +
-                       (((u64) trb->event_cmd.cmd_trb[1]) << 32);
+               address = trb->event_cmd.cmd_trb;
                xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
                xhci_dbg(xhci, "Completion status = %u\n",
                                (unsigned int) GET_COMP_CODE(trb->event_cmd.status));
@@ -328,8 +316,8 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
        for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
                trb = &seg->trbs[i];
                xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
-                               (unsigned int) trb->link.segment_ptr[0],
-                               (unsigned int) trb->link.segment_ptr[1],
+                               lower_32_bits(trb->link.segment_ptr),
+                               upper_32_bits(trb->link.segment_ptr),
                                (unsigned int) trb->link.intr_target,
                                (unsigned int) trb->link.control);
                addr += sizeof(*trb);
@@ -386,8 +374,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
                entry = &erst->entries[i];
                xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
                                (unsigned int) addr,
-                               (unsigned int) entry->seg_addr[0],
-                               (unsigned int) entry->seg_addr[1],
+                               lower_32_bits(entry->seg_addr),
+                               upper_32_bits(entry->seg_addr),
                                (unsigned int) entry->seg_size,
                                (unsigned int) entry->rsvd);
                addr += sizeof(*entry);
@@ -396,90 +384,147 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
 
 void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
 {
-       u32 val;
+       u64 val;
 
-       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
-       xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
-       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
-       xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
+       val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+       xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n",
+                       lower_32_bits(val));
+       xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n",
+                       upper_32_bits(val));
 }
 
-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
+/* Print the last 32 bytes for 64-byte contexts */
+static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
+{
+       int i;
+       for (i = 0; i < 4; ++i) {
+               xhci_dbg(xhci, "@%p (virt) @%08llx "
+                        "(dma) %#08llx - rsvd64[%d]\n",
+                        &ctx[4 + i], (unsigned long long)dma,
+                        ctx[4 + i], i);
+               dma += 8;
+       }
+}
+
+void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
 {
-       int i, j;
-       int last_ep_ctx = 31;
        /* Fields are 32 bits wide, DMA addresses are in bytes */
        int field_size = 32 / 8;
+       int i;
 
-       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
-                       &ctx->drop_flags, (unsigned long long)dma,
-                       ctx->drop_flags);
-       dma += field_size;
-       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
-                       &ctx->add_flags, (unsigned long long)dma,
-                       ctx->add_flags);
-       dma += field_size;
-       for (i = 0; i > 6; ++i) {
-               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
-                               &ctx->rsvd[i], (unsigned long long)dma,
-                               ctx->rsvd[i], i);
-               dma += field_size;
-       }
+       struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+       dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx);
+       int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
 
        xhci_dbg(xhci, "Slot Context:\n");
        xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
-                       &ctx->slot.dev_info,
-                       (unsigned long long)dma, ctx->slot.dev_info);
+                       &slot_ctx->dev_info,
+                       (unsigned long long)dma, slot_ctx->dev_info);
        dma += field_size;
        xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
-                       &ctx->slot.dev_info2,
-                       (unsigned long long)dma, ctx->slot.dev_info2);
+                       &slot_ctx->dev_info2,
+                       (unsigned long long)dma, slot_ctx->dev_info2);
        dma += field_size;
        xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
-                       &ctx->slot.tt_info,
-                       (unsigned long long)dma, ctx->slot.tt_info);
+                       &slot_ctx->tt_info,
+                       (unsigned long long)dma, slot_ctx->tt_info);
        dma += field_size;
        xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
-                       &ctx->slot.dev_state,
-                       (unsigned long long)dma, ctx->slot.dev_state);
+                       &slot_ctx->dev_state,
+                       (unsigned long long)dma, slot_ctx->dev_state);
        dma += field_size;
-       for (i = 0; i > 4; ++i) {
+       for (i = 0; i < 4; ++i) {
                xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
-                               &ctx->slot.reserved[i], (unsigned long long)dma,
-                               ctx->slot.reserved[i], i);
+                               &slot_ctx->reserved[i], (unsigned long long)dma,
+                               slot_ctx->reserved[i], i);
                dma += field_size;
        }
 
+       if (csz)
+               dbg_rsvd64(xhci, (u64 *)slot_ctx, dma);
+}
+
+void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
+                    struct xhci_container_ctx *ctx,
+                    unsigned int last_ep)
+{
+       int i, j;
+       int last_ep_ctx = 31;
+       /* Fields are 32 bits wide, DMA addresses are in bytes */
+       int field_size = 32 / 8;
+       int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+
        if (last_ep < 31)
                last_ep_ctx = last_ep + 1;
        for (i = 0; i < last_ep_ctx; ++i) {
+               struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
+               dma_addr_t dma = ctx->dma +
+                       ((unsigned long)ep_ctx - (unsigned long)ctx);
+
                xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
                xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
-                               &ctx->ep[i].ep_info,
-                               (unsigned long long)dma, ctx->ep[i].ep_info);
+                               &ep_ctx->ep_info,
+                               (unsigned long long)dma, ep_ctx->ep_info);
                dma += field_size;
                xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
-                               &ctx->ep[i].ep_info2,
-                               (unsigned long long)dma, ctx->ep[i].ep_info2);
-               dma += field_size;
-               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n",
-                               &ctx->ep[i].deq[0],
-                               (unsigned long long)dma, ctx->ep[i].deq[0]);
-               dma += field_size;
-               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n",
-                               &ctx->ep[i].deq[1],
-                               (unsigned long long)dma, ctx->ep[i].deq[1]);
+                               &ep_ctx->ep_info2,
+                               (unsigned long long)dma, ep_ctx->ep_info2);
                dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n",
+                               &ep_ctx->deq,
+                               (unsigned long long)dma, ep_ctx->deq);
+               dma += 2*field_size;
                xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
-                               &ctx->ep[i].tx_info,
-                               (unsigned long long)dma, ctx->ep[i].tx_info);
+                               &ep_ctx->tx_info,
+                               (unsigned long long)dma, ep_ctx->tx_info);
                dma += field_size;
                for (j = 0; j < 3; ++j) {
                        xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
-                                       &ctx->ep[i].reserved[j],
+                                       &ep_ctx->reserved[j],
                                        (unsigned long long)dma,
-                                       ctx->ep[i].reserved[j], j);
+                                       ep_ctx->reserved[j], j);
+                       dma += field_size;
+               }
+
+               if (csz)
+                       dbg_rsvd64(xhci, (u64 *)ep_ctx, dma);
+       }
+}
+
+void xhci_dbg_ctx(struct xhci_hcd *xhci,
+                 struct xhci_container_ctx *ctx,
+                 unsigned int last_ep)
+{
+       int i;
+       /* Fields are 32 bits wide, DMA addresses are in bytes */
+       int field_size = 32 / 8;
+       struct xhci_slot_ctx *slot_ctx;
+       dma_addr_t dma = ctx->dma;
+       int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+
+       if (ctx->type == XHCI_CTX_TYPE_INPUT) {
+               struct xhci_input_control_ctx *ctrl_ctx =
+                       xhci_get_input_control_ctx(xhci, ctx);
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
+                        &ctrl_ctx->drop_flags, (unsigned long long)dma,
+                        ctrl_ctx->drop_flags);
+               dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
+                        &ctrl_ctx->add_flags, (unsigned long long)dma,
+                        ctrl_ctx->add_flags);
+               dma += field_size;
+               for (i = 0; i < 6; ++i) {
+                       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n",
+                                &ctrl_ctx->rsvd2[i], (unsigned long long)dma,
+                                ctrl_ctx->rsvd2[i], i);
                        dma += field_size;
                }
+
+               if (csz)
+                       dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma);
        }
+
+       slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+       xhci_dbg_slot_ctx(xhci, ctx);
+       xhci_dbg_ep_ctx(xhci, ctx, last_ep);
 }
index dba3e07ccd09a1098660fb5c4a17c921deefc483..816c39caca1cf6bf5e1ca9b4a9c8c5d03684fcf3 100644 (file)
@@ -103,7 +103,10 @@ int xhci_reset(struct xhci_hcd *xhci)
        u32 state;
 
        state = xhci_readl(xhci, &xhci->op_regs->status);
-       BUG_ON((state & STS_HALT) == 0);
+       if ((state & STS_HALT) == 0) {
+               xhci_warn(xhci, "Host controller not halted, aborting reset.\n");
+               return 0;
+       }
 
        xhci_dbg(xhci, "// Reset the HC\n");
        command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -226,6 +229,7 @@ int xhci_init(struct usb_hcd *hcd)
 static void xhci_work(struct xhci_hcd *xhci)
 {
        u32 temp;
+       u64 temp_64;
 
        /*
         * Clear the op reg interrupt status first,
@@ -248,9 +252,9 @@ static void xhci_work(struct xhci_hcd *xhci)
        /* FIXME this should be a delayed service routine that clears the EHB */
        xhci_handle_event(xhci);
 
-       /* Clear the event handler busy flag; the event ring should be empty. */
-       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
-       xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]);
+       /* Clear the event handler busy flag (RW1C); the event ring should be empty. */
+       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+       xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
        /* Flush posted writes -- FIXME is this necessary? */
        xhci_readl(xhci, &xhci->ir_set->irq_pending);
 }
@@ -266,19 +270,34 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        u32 temp, temp2;
+       union xhci_trb *trb;
 
        spin_lock(&xhci->lock);
+       trb = xhci->event_ring->dequeue;
        /* Check if the xHC generated the interrupt, or the irq is shared */
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       if (temp == 0xffffffff && temp2 == 0xffffffff)
+               goto hw_died;
+
        if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
                spin_unlock(&xhci->lock);
                return IRQ_NONE;
        }
+       xhci_dbg(xhci, "op reg status = %08x\n", temp);
+       xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
+       xhci_dbg(xhci, "Event ring dequeue ptr:\n");
+       xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
+                       (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
+                       lower_32_bits(trb->link.segment_ptr),
+                       upper_32_bits(trb->link.segment_ptr),
+                       (unsigned int) trb->link.intr_target,
+                       (unsigned int) trb->link.control);
 
        if (temp & STS_FATAL) {
                xhci_warn(xhci, "WARNING: Host System Error\n");
                xhci_halt(xhci);
+hw_died:
                xhci_to_hcd(xhci)->state = HC_STATE_HALT;
                spin_unlock(&xhci->lock);
                return -ESHUTDOWN;
@@ -295,6 +314,7 @@ void xhci_event_ring_work(unsigned long arg)
 {
        unsigned long flags;
        int temp;
+       u64 temp_64;
        struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
        int i, j;
 
@@ -311,9 +331,9 @@ void xhci_event_ring_work(unsigned long arg)
        xhci_dbg(xhci, "Event ring:\n");
        xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
        xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
-       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
-       temp &= ERST_PTR_MASK;
-       xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
+       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+       temp_64 &= ~ERST_PTR_MASK;
+       xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
        xhci_dbg(xhci, "Command ring:\n");
        xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
        xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
@@ -356,6 +376,7 @@ void xhci_event_ring_work(unsigned long arg)
 int xhci_run(struct usb_hcd *hcd)
 {
        u32 temp;
+       u64 temp_64;
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        void (*doorbell)(struct xhci_hcd *) = NULL;
 
@@ -382,6 +403,20 @@ int xhci_run(struct usb_hcd *hcd)
        add_timer(&xhci->event_ring_timer);
 #endif
 
+       xhci_dbg(xhci, "Command ring memory map follows:\n");
+       xhci_debug_ring(xhci, xhci->cmd_ring);
+       xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
+       xhci_dbg_cmd_ptrs(xhci);
+
+       xhci_dbg(xhci, "ERST memory map follows:\n");
+       xhci_dbg_erst(xhci, &xhci->erst);
+       xhci_dbg(xhci, "Event ring:\n");
+       xhci_debug_ring(xhci, xhci->event_ring);
+       xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
+       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+       temp_64 &= ~ERST_PTR_MASK;
+       xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
+
        xhci_dbg(xhci, "// Set the interrupt modulation register\n");
        temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
        temp &= ~ER_IRQ_INTERVAL_MASK;
@@ -406,22 +441,6 @@ int xhci_run(struct usb_hcd *hcd)
        if (NUM_TEST_NOOPS > 0)
                doorbell = xhci_setup_one_noop(xhci);
 
-       xhci_dbg(xhci, "Command ring memory map follows:\n");
-       xhci_debug_ring(xhci, xhci->cmd_ring);
-       xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
-       xhci_dbg_cmd_ptrs(xhci);
-
-       xhci_dbg(xhci, "ERST memory map follows:\n");
-       xhci_dbg_erst(xhci, &xhci->erst);
-       xhci_dbg(xhci, "Event ring:\n");
-       xhci_debug_ring(xhci, xhci->event_ring);
-       xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
-       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
-       temp &= ERST_PTR_MASK;
-       xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
-       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]);
-       xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp);
-
        temp = xhci_readl(xhci, &xhci->op_regs->command);
        temp |= (CMD_RUN);
        xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
@@ -601,10 +620,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
                goto exit;
        }
        if (usb_endpoint_xfer_control(&urb->ep->desc))
-               ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb,
+               /* We have a spinlock and interrupts disabled, so we must pass
+                * atomic context to this function, which may allocate memory.
+                */
+               ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
                                slot_id, ep_index);
        else if (usb_endpoint_xfer_bulk(&urb->ep->desc))
-               ret = xhci_queue_bulk_tx(xhci, mem_flags, urb,
+               ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
                                slot_id, ep_index);
        else
                ret = -EINVAL;
@@ -661,8 +683,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                goto done;
 
        xhci_dbg(xhci, "Cancel URB %p\n", urb);
+       xhci_dbg(xhci, "Event ring:\n");
+       xhci_debug_ring(xhci, xhci->event_ring);
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index];
+       xhci_dbg(xhci, "Endpoint ring:\n");
+       xhci_debug_ring(xhci, ep_ring);
        td = (struct xhci_td *) urb->hcpriv;
 
        ep_ring->cancels_pending++;
@@ -696,7 +722,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        struct xhci_hcd *xhci;
-       struct xhci_device_control *in_ctx;
+       struct xhci_container_ctx *in_ctx, *out_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
+       struct xhci_slot_ctx *slot_ctx;
        unsigned int last_ctx;
        unsigned int ep_index;
        struct xhci_ep_ctx *ep_ctx;
@@ -724,31 +752,34 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        }
 
        in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+       out_ctx = xhci->devs[udev->slot_id]->out_ctx;
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
        ep_index = xhci_get_endpoint_index(&ep->desc);
-       ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+       ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
        /* If the HC already knows the endpoint is disabled,
         * or the HCD has noted it is disabled, ignore this request
         */
        if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED ||
-                       in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
+                       ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
                xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
                                __func__, ep);
                return 0;
        }
 
-       in_ctx->drop_flags |= drop_flag;
-       new_drop_flags = in_ctx->drop_flags;
+       ctrl_ctx->drop_flags |= drop_flag;
+       new_drop_flags = ctrl_ctx->drop_flags;
 
-       in_ctx->add_flags = ~drop_flag;
-       new_add_flags = in_ctx->add_flags;
+       ctrl_ctx->add_flags = ~drop_flag;
+       new_add_flags = ctrl_ctx->add_flags;
 
-       last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags);
+       last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
+       slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
        /* Update the last valid endpoint context, if we deleted the last one */
-       if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
-               in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
-               in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+       if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
+               slot_ctx->dev_info &= ~LAST_CTX_MASK;
+               slot_ctx->dev_info |= LAST_CTX(last_ctx);
        }
-       new_slot_info = in_ctx->slot.dev_info;
+       new_slot_info = slot_ctx->dev_info;
 
        xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
 
@@ -778,17 +809,22 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        struct xhci_hcd *xhci;
-       struct xhci_device_control *in_ctx;
+       struct xhci_container_ctx *in_ctx, *out_ctx;
        unsigned int ep_index;
        struct xhci_ep_ctx *ep_ctx;
+       struct xhci_slot_ctx *slot_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
        u32 added_ctxs;
        unsigned int last_ctx;
        u32 new_add_flags, new_drop_flags, new_slot_info;
        int ret = 0;
 
        ret = xhci_check_args(hcd, udev, ep, 1, __func__);
-       if (ret <= 0)
+       if (ret <= 0) {
+               /* So we won't queue a reset ep command for a root hub */
+               ep->hcpriv = NULL;
                return ret;
+       }
        xhci = hcd_to_xhci(hcd);
 
        added_ctxs = xhci_get_endpoint_flag(&ep->desc);
@@ -810,12 +846,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        }
 
        in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+       out_ctx = xhci->devs[udev->slot_id]->out_ctx;
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
        ep_index = xhci_get_endpoint_index(&ep->desc);
-       ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+       ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
        /* If the HCD has already noted the endpoint is enabled,
         * ignore this request.
         */
-       if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
+       if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
                xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
                                __func__, ep);
                return 0;
@@ -833,8 +871,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                return -ENOMEM;
        }
 
-       in_ctx->add_flags |= added_ctxs;
-       new_add_flags = in_ctx->add_flags;
+       ctrl_ctx->add_flags |= added_ctxs;
+       new_add_flags = ctrl_ctx->add_flags;
 
        /* If xhci_endpoint_disable() was called for this endpoint, but the
         * xHC hasn't been notified yet through the check_bandwidth() call,
@@ -842,14 +880,18 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
         * descriptors.  We must drop and re-add this endpoint, so we leave the
         * drop flags alone.
         */
-       new_drop_flags = in_ctx->drop_flags;
+       new_drop_flags = ctrl_ctx->drop_flags;
 
+       slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
        /* Update the last valid endpoint context, if we just added one past */
-       if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
-               in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
-               in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+       if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
+               slot_ctx->dev_info &= ~LAST_CTX_MASK;
+               slot_ctx->dev_info |= LAST_CTX(last_ctx);
        }
-       new_slot_info = in_ctx->slot.dev_info;
+       new_slot_info = slot_ctx->dev_info;
+
+       /* Store the usb_device pointer for later use */
+       ep->hcpriv = udev;
 
        xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
                        (unsigned int) ep->desc.bEndpointAddress,
@@ -860,9 +902,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        return 0;
 }
 
-static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)
+static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev)
 {
+       struct xhci_input_control_ctx *ctrl_ctx;
        struct xhci_ep_ctx *ep_ctx;
+       struct xhci_slot_ctx *slot_ctx;
        int i;
 
        /* When a device's add flag and drop flag are zero, any subsequent
@@ -870,17 +914,18 @@ static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)
         * untouched.  Make sure we don't leave any old state in the input
         * endpoint contexts.
         */
-       virt_dev->in_ctx->drop_flags = 0;
-       virt_dev->in_ctx->add_flags = 0;
-       virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+       ctrl_ctx->drop_flags = 0;
+       ctrl_ctx->add_flags = 0;
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+       slot_ctx->dev_info &= ~LAST_CTX_MASK;
        /* Endpoint 0 is always valid */
-       virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+       slot_ctx->dev_info |= LAST_CTX(1);
        for (i = 1; i < 31; ++i) {
-               ep_ctx = &virt_dev->in_ctx->ep[i];
+               ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i);
                ep_ctx->ep_info = 0;
                ep_ctx->ep_info2 = 0;
-               ep_ctx->deq[0] = 0;
-               ep_ctx->deq[1] = 0;
+               ep_ctx->deq = 0;
                ep_ctx->tx_info = 0;
        }
 }
@@ -903,6 +948,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
        unsigned long flags;
        struct xhci_hcd *xhci;
        struct xhci_virt_device *virt_dev;
+       struct xhci_input_control_ctx *ctrl_ctx;
+       struct xhci_slot_ctx *slot_ctx;
 
        ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
        if (ret <= 0)
@@ -918,16 +965,18 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
        virt_dev = xhci->devs[udev->slot_id];
 
        /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
-       virt_dev->in_ctx->add_flags |= SLOT_FLAG;
-       virt_dev->in_ctx->add_flags &= ~EP0_FLAG;
-       virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG;
-       virt_dev->in_ctx->drop_flags &= ~EP0_FLAG;
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+       ctrl_ctx->add_flags |= SLOT_FLAG;
+       ctrl_ctx->add_flags &= ~EP0_FLAG;
+       ctrl_ctx->drop_flags &= ~SLOT_FLAG;
+       ctrl_ctx->drop_flags &= ~EP0_FLAG;
        xhci_dbg(xhci, "New Input Control Context:\n");
-       xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma,
-                       LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx,
+                       LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
 
        spin_lock_irqsave(&xhci->lock, flags);
-       ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma,
+       ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
                        udev->slot_id);
        if (ret < 0) {
                spin_unlock_irqrestore(&xhci->lock, flags);
@@ -982,10 +1031,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
        }
 
        xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
-       xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma,
-                       LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+       xhci_dbg_ctx(xhci, virt_dev->out_ctx,
+                       LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
 
-       xhci_zero_in_ctx(virt_dev);
+       xhci_zero_in_ctx(xhci, virt_dev);
        /* Free any old rings */
        for (i = 1; i < 31; ++i) {
                if (virt_dev->new_ep_rings[i]) {
@@ -1023,7 +1072,67 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
                        virt_dev->new_ep_rings[i] = NULL;
                }
        }
-       xhci_zero_in_ctx(virt_dev);
+       xhci_zero_in_ctx(xhci, virt_dev);
+}
+
+/* Deal with stalled endpoints.  The core should have sent the control message
+ * to clear the halt condition.  However, we need to make the xHCI hardware
+ * reset its sequence number, since a device will expect a sequence number of
+ * zero after the halt condition is cleared.
+ * Context: in_interrupt
+ */
+void xhci_endpoint_reset(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct xhci_hcd *xhci;
+       struct usb_device *udev;
+       unsigned int ep_index;
+       unsigned long flags;
+       int ret;
+       struct xhci_dequeue_state deq_state;
+       struct xhci_ring *ep_ring;
+
+       xhci = hcd_to_xhci(hcd);
+       udev = (struct usb_device *) ep->hcpriv;
+       /* Called with a root hub endpoint (or an endpoint that wasn't added
+        * with xhci_add_endpoint()
+        */
+       if (!ep->hcpriv)
+               return;
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+       ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index];
+       if (!ep_ring->stopped_td) {
+               xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
+                               ep->desc.bEndpointAddress);
+               return;
+       }
+
+       xhci_dbg(xhci, "Queueing reset endpoint command\n");
+       spin_lock_irqsave(&xhci->lock, flags);
+       ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
+       /*
+        * Can't change the ring dequeue pointer until it's transitioned to the
+        * stopped state, which is only upon a successful reset endpoint
+        * command.  Better hope that last command worked!
+        */
+       if (!ret) {
+               xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+               /* We need to move the HW's dequeue pointer past this TD,
+                * or it will attempt to resend it on the next doorbell ring.
+                */
+               xhci_find_new_dequeue_state(xhci, udev->slot_id,
+                               ep_index, ep_ring->stopped_td, &deq_state);
+               xhci_dbg(xhci, "Queueing new dequeue state\n");
+               xhci_queue_new_dequeue_state(xhci, ep_ring,
+                               udev->slot_id,
+                               ep_index, &deq_state);
+               kfree(ep_ring->stopped_td);
+               xhci_ring_cmd_db(xhci);
+       }
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
+       if (ret)
+               xhci_warn(xhci, "FIXME allocate a new ring segment\n");
 }
 
 /*
@@ -1120,7 +1229,9 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        struct xhci_virt_device *virt_dev;
        int ret = 0;
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-       u32 temp;
+       struct xhci_slot_ctx *slot_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
+       u64 temp_64;
 
        if (!udev->slot_id) {
                xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
@@ -1133,10 +1244,12 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        if (!udev->config)
                xhci_setup_addressable_virt_dev(xhci, udev);
        /* Otherwise, assume the core has the device configured how it wants */
+       xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
 
        spin_lock_irqsave(&xhci->lock, flags);
-       ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma,
-                       udev->slot_id);
+       ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
+                                       udev->slot_id);
        if (ret) {
                spin_unlock_irqrestore(&xhci->lock, flags);
                xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
@@ -1176,41 +1289,37 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        default:
                xhci_err(xhci, "ERROR: unexpected command completion "
                                "code 0x%x.\n", virt_dev->cmd_status);
+               xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
+               xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
                ret = -EINVAL;
                break;
        }
        if (ret) {
                return ret;
        }
-       temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]);
-       xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp);
-       temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]);
-       xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp);
-       xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n",
-                       udev->slot_id,
-                       &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id],
-                       xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]);
-       xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n",
+       temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
+       xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
+       xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
                        udev->slot_id,
-                       &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1],
-                       xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]);
+                       &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+                       (unsigned long long)
+                               xhci->dcbaa->dev_context_ptrs[udev->slot_id]);
        xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
-                       (unsigned long long)virt_dev->out_ctx_dma);
+                       (unsigned long long)virt_dev->out_ctx->dma);
        xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
-       xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2);
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
        xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
-       xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2);
+       xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
        /*
         * USB core uses address 1 for the roothubs, so we add one to the
         * address given back to us by the HC.
         */
-       udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1;
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+       udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
        /* Zero the input context control for later use */
-       virt_dev->in_ctx->add_flags = 0;
-       virt_dev->in_ctx->drop_flags = 0;
-       /* Mirror flags in the output context for future ep enable/disable */
-       virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
-       virt_dev->out_ctx->drop_flags = 0;
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+       ctrl_ctx->add_flags = 0;
+       ctrl_ctx->drop_flags = 0;
 
        xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
        /* XXX Meh, not sure if anyone else but choose_address uses this. */
@@ -1252,7 +1361,6 @@ static int __init xhci_hcd_init(void)
        /* xhci_device_control has eight fields, and also
         * embeds one xhci_slot_ctx and 31 xhci_ep_ctx
         */
-       BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8);
        BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
        BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
        BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
index c8a72de1c5087c58a9fd7f5fba56d9073c1af040..e6b9a1c6002d3da5b43c65161cca881d18a8e214 100644 (file)
@@ -88,7 +88,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
                return;
        prev->next = next;
        if (link_trbs) {
-               prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma;
+               prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;
 
                /* Set the last TRB in the segment to have a TRB type ID of Link TRB */
                val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
@@ -189,6 +189,63 @@ fail:
        return 0;
 }
 
+#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
+
+struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+                                                   int type, gfp_t flags)
+{
+       struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags);
+       if (!ctx)
+               return NULL;
+
+       BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
+       ctx->type = type;
+       ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+       if (type == XHCI_CTX_TYPE_INPUT)
+               ctx->size += CTX_SIZE(xhci->hcc_params);
+
+       ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma);
+       memset(ctx->bytes, 0, ctx->size);
+       return ctx;
+}
+
+void xhci_free_container_ctx(struct xhci_hcd *xhci,
+                            struct xhci_container_ctx *ctx)
+{
+       dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma);
+       kfree(ctx);
+}
+
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci,
+                                             struct xhci_container_ctx *ctx)
+{
+       BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT);
+       return (struct xhci_input_control_ctx *)ctx->bytes;
+}
+
+struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci,
+                                       struct xhci_container_ctx *ctx)
+{
+       if (ctx->type == XHCI_CTX_TYPE_DEVICE)
+               return (struct xhci_slot_ctx *)ctx->bytes;
+
+       return (struct xhci_slot_ctx *)
+               (ctx->bytes + CTX_SIZE(xhci->hcc_params));
+}
+
+struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
+                                   struct xhci_container_ctx *ctx,
+                                   unsigned int ep_index)
+{
+       /* increment ep index by offset of start of ep ctx array */
+       ep_index++;
+       if (ctx->type == XHCI_CTX_TYPE_INPUT)
+               ep_index++;
+
+       return (struct xhci_ep_ctx *)
+               (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params)));
+}
+
 /* All the xhci_tds in the ring's TD list should be freed at this point */
 void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
 {
@@ -200,8 +257,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
                return;
 
        dev = xhci->devs[slot_id];
-       xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0;
-       xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+       xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
        if (!dev)
                return;
 
@@ -210,11 +266,10 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
                        xhci_ring_free(xhci, dev->ep_rings[i]);
 
        if (dev->in_ctx)
-               dma_pool_free(xhci->device_pool,
-                               dev->in_ctx, dev->in_ctx_dma);
+               xhci_free_container_ctx(xhci, dev->in_ctx);
        if (dev->out_ctx)
-               dma_pool_free(xhci->device_pool,
-                               dev->out_ctx, dev->out_ctx_dma);
+               xhci_free_container_ctx(xhci, dev->out_ctx);
+
        kfree(xhci->devs[slot_id]);
        xhci->devs[slot_id] = 0;
 }
@@ -222,7 +277,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
 int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
                struct usb_device *udev, gfp_t flags)
 {
-       dma_addr_t      dma;
        struct xhci_virt_device *dev;
 
        /* Slot ID 0 is reserved */
@@ -236,23 +290,21 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
                return 0;
        dev = xhci->devs[slot_id];
 
-       /* Allocate the (output) device context that will be used in the HC */
-       dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+       /* Allocate the (output) device context that will be used in the HC. */
+       dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
        if (!dev->out_ctx)
                goto fail;
-       dev->out_ctx_dma = dma;
+
        xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
-                       (unsigned long long)dma);
-       memset(dev->out_ctx, 0, sizeof(*dev->out_ctx));
+                       (unsigned long long)dev->out_ctx->dma);
 
        /* Allocate the (input) device context for address device command */
-       dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+       dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags);
        if (!dev->in_ctx)
                goto fail;
-       dev->in_ctx_dma = dma;
+
        xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
-                       (unsigned long long)dma);
-       memset(dev->in_ctx, 0, sizeof(*dev->in_ctx));
+                       (unsigned long long)dev->in_ctx->dma);
 
        /* Allocate endpoint 0 ring */
        dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags);
@@ -261,17 +313,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
 
        init_completion(&dev->cmd_completion);
 
-       /*
-        * Point to output device context in dcbaa; skip the output control
-        * context, which is eight 32 bit fields (or 32 bytes long)
-        */
-       xhci->dcbaa->dev_context_ptrs[2*slot_id] =
-               (u32) dev->out_ctx_dma + (32);
+       /* Point to output device context in dcbaa. */
+       xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
        xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
                        slot_id,
-                       &xhci->dcbaa->dev_context_ptrs[2*slot_id],
-                       (unsigned long long)dev->out_ctx_dma);
-       xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+                       &xhci->dcbaa->dev_context_ptrs[slot_id],
+                       (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
 
        return 1;
 fail:
@@ -285,6 +332,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        struct xhci_virt_device *dev;
        struct xhci_ep_ctx      *ep0_ctx;
        struct usb_device       *top_dev;
+       struct xhci_slot_ctx    *slot_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
 
        dev = xhci->devs[udev->slot_id];
        /* Slot ID 0 is reserved */
@@ -293,27 +342,29 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
                                udev->slot_id);
                return -EINVAL;
        }
-       ep0_ctx = &dev->in_ctx->ep[0];
+       ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0);
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx);
+       slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
 
        /* 2) New slot context and endpoint 0 context are valid*/
-       dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+       ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
 
        /* 3) Only the control endpoint is valid - one endpoint context */
-       dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+       slot_ctx->dev_info |= LAST_CTX(1);
 
        switch (udev->speed) {
        case USB_SPEED_SUPER:
-               dev->in_ctx->slot.dev_info |= (u32) udev->route;
-               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS;
+               slot_ctx->dev_info |= (u32) udev->route;
+               slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
                break;
        case USB_SPEED_HIGH:
-               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS;
+               slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;
                break;
        case USB_SPEED_FULL:
-               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS;
+               slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;
                break;
        case USB_SPEED_LOW:
-               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS;
+               slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
                break;
        case USB_SPEED_VARIABLE:
                xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -327,7 +378,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
                        top_dev = top_dev->parent)
                /* Found device below root hub */;
-       dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
+       slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
        xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
 
        /* Is this a LS/FS device under a HS hub? */
@@ -337,8 +388,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
         */
        if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
                        udev->tt) {
-               dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id;
-               dev->in_ctx->slot.tt_info |= udev->ttport << 8;
+               slot_ctx->tt_info = udev->tt->hub->slot_id;
+               slot_ctx->tt_info |= udev->ttport << 8;
        }
        xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
        xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
@@ -360,10 +411,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        ep0_ctx->ep_info2 |= MAX_BURST(0);
        ep0_ctx->ep_info2 |= ERROR_COUNT(3);
 
-       ep0_ctx->deq[0] =
+       ep0_ctx->deq =
                dev->ep_rings[0]->first_seg->dma;
-       ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state;
-       ep0_ctx->deq[1] = 0;
+       ep0_ctx->deq |= dev->ep_rings[0]->cycle_state;
 
        /* Steps 7 and 8 were done in xhci_alloc_virt_device() */
 
@@ -470,25 +520,26 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
        unsigned int max_burst;
 
        ep_index = xhci_get_endpoint_index(&ep->desc);
-       ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+       ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
 
        /* Set up the endpoint ring */
        virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);
        if (!virt_dev->new_ep_rings[ep_index])
                return -ENOMEM;
        ep_ring = virt_dev->new_ep_rings[ep_index];
-       ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state;
-       ep_ctx->deq[1] = 0;
+       ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
 
        ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
 
        /* FIXME dig Mult and streams info out of ep companion desc */
 
-       /* Allow 3 retries for everything but isoc */
+       /* Allow 3 retries for everything but isoc;
+        * error count = 0 means infinite retries.
+        */
        if (!usb_endpoint_xfer_isoc(&ep->desc))
                ep_ctx->ep_info2 = ERROR_COUNT(3);
        else
-               ep_ctx->ep_info2 = ERROR_COUNT(0);
+               ep_ctx->ep_info2 = ERROR_COUNT(1);
 
        ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
 
@@ -498,7 +549,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                max_packet = ep->desc.wMaxPacketSize;
                ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
                /* dig out max burst from ep companion desc */
-               max_packet = ep->ss_ep_comp->desc.bMaxBurst;
+               if (!ep->ss_ep_comp) {
+                       xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n");
+                       max_packet = 0;
+               } else {
+                       max_packet = ep->ss_ep_comp->desc.bMaxBurst;
+               }
                ep_ctx->ep_info2 |= MAX_BURST(max_packet);
                break;
        case USB_SPEED_HIGH:
@@ -531,18 +587,114 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
        struct xhci_ep_ctx *ep_ctx;
 
        ep_index = xhci_get_endpoint_index(&ep->desc);
-       ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+       ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
 
        ep_ctx->ep_info = 0;
        ep_ctx->ep_info2 = 0;
-       ep_ctx->deq[0] = 0;
-       ep_ctx->deq[1] = 0;
+       ep_ctx->deq = 0;
        ep_ctx->tx_info = 0;
        /* Don't free the endpoint ring until the set interface or configuration
         * request succeeds.
         */
 }
 
+/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
+static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
+{
+       int i;
+       struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+
+       xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp);
+
+       if (!num_sp)
+               return 0;
+
+       xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags);
+       if (!xhci->scratchpad)
+               goto fail_sp;
+
+       xhci->scratchpad->sp_array =
+               pci_alloc_consistent(to_pci_dev(dev),
+                                    num_sp * sizeof(u64),
+                                    &xhci->scratchpad->sp_dma);
+       if (!xhci->scratchpad->sp_array)
+               goto fail_sp2;
+
+       xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags);
+       if (!xhci->scratchpad->sp_buffers)
+               goto fail_sp3;
+
+       xhci->scratchpad->sp_dma_buffers =
+               kzalloc(sizeof(dma_addr_t) * num_sp, flags);
+
+       if (!xhci->scratchpad->sp_dma_buffers)
+               goto fail_sp4;
+
+       xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma;
+       for (i = 0; i < num_sp; i++) {
+               dma_addr_t dma;
+               void *buf = pci_alloc_consistent(to_pci_dev(dev),
+                                                xhci->page_size, &dma);
+               if (!buf)
+                       goto fail_sp5;
+
+               xhci->scratchpad->sp_array[i] = dma;
+               xhci->scratchpad->sp_buffers[i] = buf;
+               xhci->scratchpad->sp_dma_buffers[i] = dma;
+       }
+
+       return 0;
+
+ fail_sp5:
+       for (i = i - 1; i >= 0; i--) {
+               pci_free_consistent(to_pci_dev(dev), xhci->page_size,
+                                   xhci->scratchpad->sp_buffers[i],
+                                   xhci->scratchpad->sp_dma_buffers[i]);
+       }
+       kfree(xhci->scratchpad->sp_dma_buffers);
+
+ fail_sp4:
+       kfree(xhci->scratchpad->sp_buffers);
+
+ fail_sp3:
+       pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64),
+                           xhci->scratchpad->sp_array,
+                           xhci->scratchpad->sp_dma);
+
+ fail_sp2:
+       kfree(xhci->scratchpad);
+       xhci->scratchpad = NULL;
+
+ fail_sp:
+       return -ENOMEM;
+}
+
+static void scratchpad_free(struct xhci_hcd *xhci)
+{
+       int num_sp;
+       int i;
+       struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+       if (!xhci->scratchpad)
+               return;
+
+       num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+
+       for (i = 0; i < num_sp; i++) {
+               pci_free_consistent(pdev, xhci->page_size,
+                                   xhci->scratchpad->sp_buffers[i],
+                                   xhci->scratchpad->sp_dma_buffers[i]);
+       }
+       kfree(xhci->scratchpad->sp_dma_buffers);
+       kfree(xhci->scratchpad->sp_buffers);
+       pci_free_consistent(pdev, num_sp * sizeof(u64),
+                           xhci->scratchpad->sp_array,
+                           xhci->scratchpad->sp_dma);
+       kfree(xhci->scratchpad);
+       xhci->scratchpad = NULL;
+}
+
 void xhci_mem_cleanup(struct xhci_hcd *xhci)
 {
        struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
@@ -551,10 +703,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
        /* Free the Event Ring Segment Table and the actual Event Ring */
        xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]);
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]);
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
+       xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
+       xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
        size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
        if (xhci->erst.entries)
                pci_free_consistent(pdev, size,
@@ -566,8 +716,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        xhci->event_ring = NULL;
        xhci_dbg(xhci, "Freed event ring\n");
 
-       xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]);
-       xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]);
+       xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
        if (xhci->cmd_ring)
                xhci_ring_free(xhci, xhci->cmd_ring);
        xhci->cmd_ring = NULL;
@@ -586,8 +735,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        xhci->device_pool = NULL;
        xhci_dbg(xhci, "Freed device context pool\n");
 
-       xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]);
-       xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]);
+       xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
        if (xhci->dcbaa)
                pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
                                xhci->dcbaa, xhci->dcbaa->dma);
@@ -595,6 +743,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
        xhci->page_size = 0;
        xhci->page_shift = 0;
+       scratchpad_free(xhci);
 }
 
 int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
@@ -602,6 +751,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        dma_addr_t      dma;
        struct device   *dev = xhci_to_hcd(xhci)->self.controller;
        unsigned int    val, val2;
+       u64             val_64;
        struct xhci_segment     *seg;
        u32 page_size;
        int i;
@@ -647,8 +797,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        xhci->dcbaa->dma = dma;
        xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
                        (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
-       xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]);
-       xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]);
+       xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
 
        /*
         * Initialize the ring segment pool.  The ring must be a contiguous
@@ -658,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
         */
        xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
                        SEGMENT_SIZE, 64, xhci->page_size);
+
        /* See Table 46 and Note on Figure 55 */
-       /* FIXME support 64-byte contexts */
        xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
-                       sizeof(struct xhci_device_control),
-                       64, xhci->page_size);
+                       2112, 64, xhci->page_size);
        if (!xhci->segment_pool || !xhci->device_pool)
                goto fail;
 
@@ -675,14 +823,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                        (unsigned long long)xhci->cmd_ring->first_seg->dma);
 
        /* Set the address in the Command Ring Control register */
-       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
-       val = (val & ~CMD_RING_ADDR_MASK) |
-               (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) |
+       val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+       val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+               (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
                xhci->cmd_ring->cycle_state;
-       xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val);
-       xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]);
-       xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n");
-       xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]);
+       xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val);
+       xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
        xhci_dbg_cmd_ptrs(xhci);
 
        val = xhci_readl(xhci, &xhci->cap_regs->db_off);
@@ -722,8 +868,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        /* set ring base address and size for each segment table entry */
        for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
                struct xhci_erst_entry *entry = &xhci->erst.entries[val];
-               entry->seg_addr[0] = seg->dma;
-               entry->seg_addr[1] = 0;
+               entry->seg_addr = seg->dma;
                entry->seg_size = TRBS_PER_SEGMENT;
                entry->rsvd = 0;
                seg = seg->next;
@@ -741,11 +886,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        /* set the segment table base address */
        xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
                        (unsigned long long)xhci->erst.erst_dma_addr);
-       val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]);
-       val &= ERST_PTR_MASK;
-       val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK);
-       xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]);
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
+       val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+       val_64 &= ERST_PTR_MASK;
+       val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
+       xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
 
        /* Set the event ring dequeue address */
        xhci_set_hc_event_deq(xhci);
@@ -761,7 +905,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        for (i = 0; i < MAX_HC_SLOTS; ++i)
                xhci->devs[i] = 0;
 
+       if (scratchpad_alloc(xhci, flags))
+               goto fail;
+
        return 0;
+
 fail:
        xhci_warn(xhci, "Couldn't initialize memory\n");
        xhci_mem_cleanup(xhci);
index 1462709e26c0411cfc69d13b93641f2764eeb096..592fe7e623f7a0d8f863a5d72a67dae42c4ea7aa 100644 (file)
@@ -117,6 +117,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
        .free_dev =             xhci_free_dev,
        .add_endpoint =         xhci_add_endpoint,
        .drop_endpoint =        xhci_drop_endpoint,
+       .endpoint_reset =       xhci_endpoint_reset,
        .check_bandwidth =      xhci_check_bandwidth,
        .reset_bandwidth =      xhci_reset_bandwidth,
        .address_device =       xhci_address_device,
index 02d81985c4544071b2abc9899a6661d802629b6b..aa88a067148bb70584bdaaaf9c56ccb39b32d3c3 100644 (file)
@@ -135,6 +135,7 @@ static void next_trb(struct xhci_hcd *xhci,
 static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
 {
        union xhci_trb *next = ++(ring->dequeue);
+       unsigned long long addr;
 
        ring->deq_updates++;
        /* Update the dequeue pointer further if that was a link TRB or we're at
@@ -152,6 +153,13 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
                ring->dequeue = ring->deq_seg->trbs;
                next = ring->dequeue;
        }
+       addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
+       if (ring == xhci->event_ring)
+               xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr);
+       else if (ring == xhci->cmd_ring)
+               xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr);
+       else
+               xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr);
 }
 
 /*
@@ -171,6 +179,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
 {
        u32 chain;
        union xhci_trb *next;
+       unsigned long long addr;
 
        chain = ring->enqueue->generic.field[3] & TRB_CHAIN;
        next = ++(ring->enqueue);
@@ -204,6 +213,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
                ring->enqueue = ring->enq_seg->trbs;
                next = ring->enqueue;
        }
+       addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
+       if (ring == xhci->event_ring)
+               xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr);
+       else if (ring == xhci->cmd_ring)
+               xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr);
+       else
+               xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr);
 }
 
 /*
@@ -237,7 +253,7 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 
 void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
 {
-       u32 temp;
+       u64 temp;
        dma_addr_t deq;
 
        deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
@@ -246,13 +262,15 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
                xhci_warn(xhci, "WARN something wrong with SW event ring "
                                "dequeue ptr.\n");
        /* Update HC event ring dequeue pointer */
-       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+       temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        temp &= ERST_PTR_MASK;
-       if (!in_interrupt())
-               xhci_dbg(xhci, "// Write event ring dequeue pointer\n");
-       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
-       xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp,
-                       &xhci->ir_set->erst_dequeue[0]);
+       /* Don't clear the EHB bit (which is RW1C) because
+        * there might be more events to service.
+        */
+       temp &= ~ERST_EHB;
+       xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n");
+       xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+                       &xhci->ir_set->erst_dequeue);
 }
 
 /* Ring the host controller doorbell after placing a command on the ring */
@@ -279,7 +297,8 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci,
        /* Don't ring the doorbell for this endpoint if there are pending
         * cancellations because the we don't want to interrupt processing.
         */
-       if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) {
+       if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)
+                       && !(ep_ring->state & EP_HALTED)) {
                field = xhci_readl(xhci, db_addr) & DB_MASK;
                xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
                /* Flush PCI posted writes - FIXME Matthew Wilcox says this
@@ -316,12 +335,6 @@ static struct xhci_segment *find_trb_seg(
        return cur_seg;
 }
 
-struct dequeue_state {
-       struct xhci_segment *new_deq_seg;
-       union xhci_trb *new_deq_ptr;
-       int new_cycle_state;
-};
-
 /*
  * Move the xHC's endpoint ring dequeue pointer past cur_td.
  * Record the new state of the xHC's endpoint ring dequeue segment,
@@ -336,24 +349,30 @@ struct dequeue_state {
  *  - Finally we move the dequeue state one TRB further, toggling the cycle bit
  *    if we've moved it past a link TRB with the toggle cycle bit set.
  */
-static void find_new_dequeue_state(struct xhci_hcd *xhci,
+void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
-               struct xhci_td *cur_td, struct dequeue_state *state)
+               struct xhci_td *cur_td, struct xhci_dequeue_state *state)
 {
        struct xhci_virt_device *dev = xhci->devs[slot_id];
        struct xhci_ring *ep_ring = dev->ep_rings[ep_index];
        struct xhci_generic_trb *trb;
+       struct xhci_ep_ctx *ep_ctx;
+       dma_addr_t addr;
 
        state->new_cycle_state = 0;
+       xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
        state->new_deq_seg = find_trb_seg(cur_td->start_seg,
                        ep_ring->stopped_trb,
                        &state->new_cycle_state);
        if (!state->new_deq_seg)
                BUG();
        /* Dig out the cycle state saved by the xHC during the stop ep cmd */
-       state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0];
+       xhci_dbg(xhci, "Finding endpoint context\n");
+       ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+       state->new_cycle_state = 0x1 & ep_ctx->deq;
 
        state->new_deq_ptr = cur_td->last_trb;
+       xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
        state->new_deq_seg = find_trb_seg(state->new_deq_seg,
                        state->new_deq_ptr,
                        &state->new_cycle_state);
@@ -367,6 +386,12 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci,
        next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
 
        /* Don't update the ring cycle state for the producer (us). */
+       xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n",
+                       state->new_deq_seg);
+       addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr);
+       xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n",
+                       (unsigned long long) addr);
+       xhci_dbg(xhci, "Setting dequeue pointer in internal ring state.\n");
        ep_ring->dequeue = state->new_deq_ptr;
        ep_ring->deq_seg = state->new_deq_seg;
 }
@@ -416,6 +441,30 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
                unsigned int ep_index, struct xhci_segment *deq_seg,
                union xhci_trb *deq_ptr, u32 cycle_state);
 
+void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
+               struct xhci_ring *ep_ring, unsigned int slot_id,
+               unsigned int ep_index, struct xhci_dequeue_state *deq_state)
+{
+       xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+                       "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+                       deq_state->new_deq_seg,
+                       (unsigned long long)deq_state->new_deq_seg->dma,
+                       deq_state->new_deq_ptr,
+                       (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr),
+                       deq_state->new_cycle_state);
+       queue_set_tr_deq(xhci, slot_id, ep_index,
+                       deq_state->new_deq_seg,
+                       deq_state->new_deq_ptr,
+                       (u32) deq_state->new_cycle_state);
+       /* Stop the TD queueing code from ringing the doorbell until
+        * this command completes.  The HC won't set the dequeue pointer
+        * if the ring is running, and ringing the doorbell starts the
+        * ring running.
+        */
+       ep_ring->state |= SET_DEQ_PENDING;
+       xhci_ring_cmd_db(xhci);
+}
+
 /*
  * When we get a command completion for a Stop Endpoint Command, we need to
  * unlink any cancelled TDs from the ring.  There are two ways to do that:
@@ -436,7 +485,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
        struct xhci_td *cur_td = 0;
        struct xhci_td *last_unlinked_td;
 
-       struct dequeue_state deq_state;
+       struct xhci_dequeue_state deq_state;
 #ifdef CONFIG_USB_HCD_STAT
        ktime_t stop_time = ktime_get();
 #endif
@@ -464,7 +513,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
                 * move the xHC endpoint ring dequeue pointer past this TD.
                 */
                if (cur_td == ep_ring->stopped_td)
-                       find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
+                       xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
                                        &deq_state);
                else
                        td_to_noop(xhci, ep_ring, cur_td);
@@ -480,24 +529,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
 
        /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
        if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
-               xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
-                               "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
-                               deq_state.new_deq_seg,
-                               (unsigned long long)deq_state.new_deq_seg->dma,
-                               deq_state.new_deq_ptr,
-                               (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr),
-                               deq_state.new_cycle_state);
-               queue_set_tr_deq(xhci, slot_id, ep_index,
-                               deq_state.new_deq_seg,
-                               deq_state.new_deq_ptr,
-                               (u32) deq_state.new_cycle_state);
-               /* Stop the TD queueing code from ringing the doorbell until
-                * this command completes.  The HC won't set the dequeue pointer
-                * if the ring is running, and ringing the doorbell starts the
-                * ring running.
-                */
-               ep_ring->state |= SET_DEQ_PENDING;
-               xhci_ring_cmd_db(xhci);
+               xhci_queue_new_dequeue_state(xhci, ep_ring,
+                               slot_id, ep_index, &deq_state);
        } else {
                /* Otherwise just ring the doorbell to restart the ring */
                ring_ep_doorbell(xhci, slot_id, ep_index);
@@ -551,11 +584,15 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
        unsigned int ep_index;
        struct xhci_ring *ep_ring;
        struct xhci_virt_device *dev;
+       struct xhci_ep_ctx *ep_ctx;
+       struct xhci_slot_ctx *slot_ctx;
 
        slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
        ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
        dev = xhci->devs[slot_id];
        ep_ring = dev->ep_rings[ep_index];
+       ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+       slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
 
        if (GET_COMP_CODE(event->status) != COMP_SUCCESS) {
                unsigned int ep_state;
@@ -569,9 +606,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
                case COMP_CTX_STATE:
                        xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "
                                        "to incorrect slot or ep state.\n");
-                       ep_state = dev->out_ctx->ep[ep_index].ep_info;
+                       ep_state = ep_ctx->ep_info;
                        ep_state &= EP_STATE_MASK;
-                       slot_state = dev->out_ctx->slot.dev_state;
+                       slot_state = slot_ctx->dev_state;
                        slot_state = GET_SLOT_STATE(slot_state);
                        xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
                                        slot_state, ep_state);
@@ -593,16 +630,33 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
                 * cancelling URBs, which might not be an error...
                 */
        } else {
-               xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, "
-                               "deq[1] = 0x%x.\n",
-                               dev->out_ctx->ep[ep_index].deq[0],
-                               dev->out_ctx->ep[ep_index].deq[1]);
+               xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
+                               ep_ctx->deq);
        }
 
        ep_ring->state &= ~SET_DEQ_PENDING;
        ring_ep_doorbell(xhci, slot_id, ep_index);
 }
 
+static void handle_reset_ep_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event,
+               union xhci_trb *trb)
+{
+       int slot_id;
+       unsigned int ep_index;
+
+       slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
+       ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+       /* This command will only fail if the endpoint wasn't halted,
+        * but we don't care.
+        */
+       xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
+                       (unsigned int) GET_COMP_CODE(event->status));
+
+       /* Clear our internal halted state and restart the ring */
+       xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED;
+       ring_ep_doorbell(xhci, slot_id, ep_index);
+}
 
 static void handle_cmd_completion(struct xhci_hcd *xhci,
                struct xhci_event_cmd *event)
@@ -611,7 +665,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
        u64 cmd_dma;
        dma_addr_t cmd_dequeue_dma;
 
-       cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0];
+       cmd_dma = event->cmd_trb;
        cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
                        xhci->cmd_ring->dequeue);
        /* Is the command ring deq ptr out of sync with the deq seg ptr? */
@@ -653,6 +707,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
        case TRB_TYPE(TRB_CMD_NOOP):
                ++xhci->noops_handled;
                break;
+       case TRB_TYPE(TRB_RESET_EP):
+               handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue);
+               break;
        default:
                /* Skip over unknown commands on the event ring */
                xhci->error_bitmask |= 1 << 6;
@@ -756,7 +813,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        union xhci_trb *event_trb;
        struct urb *urb = 0;
        int status = -EINPROGRESS;
+       struct xhci_ep_ctx *ep_ctx;
 
+       xhci_dbg(xhci, "In %s\n", __func__);
        xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
        if (!xdev) {
                xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
@@ -765,17 +824,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 
        /* Endpoint ID is 1 based, our index is zero based */
        ep_index = TRB_TO_EP_ID(event->flags) - 1;
+       xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
        ep_ring = xdev->ep_rings[ep_index];
-       if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
+       ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
+       if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
                xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");
                return -ENODEV;
        }
 
-       event_dma = event->buffer[0];
-       if (event->buffer[1] != 0)
-               xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n");
-
+       event_dma = event->buffer;
        /* This TRB should be in the TD at the head of this ring's TD list */
+       xhci_dbg(xhci, "%s - checking for list empty\n", __func__);
        if (list_empty(&ep_ring->td_list)) {
                xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
                                TRB_TO_SLOT_ID(event->flags), ep_index);
@@ -785,11 +844,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                urb = NULL;
                goto cleanup;
        }
+       xhci_dbg(xhci, "%s - getting list entry\n", __func__);
        td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
 
        /* Is this a TRB in the currently executing TD? */
+       xhci_dbg(xhci, "%s - looking for TD\n", __func__);
        event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
                        td->last_trb, event_dma);
+       xhci_dbg(xhci, "%s - found event_seg = %p\n", __func__, event_seg);
        if (!event_seg) {
                /* HC is busted, give up! */
                xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n");
@@ -798,10 +860,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)];
        xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
                        (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
-       xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n",
-                       (unsigned int) event->buffer[0]);
-       xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n",
-                       (unsigned int) event->buffer[1]);
+       xhci_dbg(xhci, "Offset 0x00 (buffer lo) = 0x%x\n",
+                       lower_32_bits(event->buffer));
+       xhci_dbg(xhci, "Offset 0x04 (buffer hi) = 0x%x\n",
+                       upper_32_bits(event->buffer));
        xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n",
                        (unsigned int) event->transfer_len);
        xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n",
@@ -823,6 +885,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                break;
        case COMP_STALL:
                xhci_warn(xhci, "WARN: Stalled endpoint\n");
+               ep_ring->state |= EP_HALTED;
                status = -EPIPE;
                break;
        case COMP_TRB_ERR:
@@ -833,6 +896,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                xhci_warn(xhci, "WARN: transfer error on endpoint\n");
                status = -EPROTO;
                break;
+       case COMP_BABBLE:
+               xhci_warn(xhci, "WARN: babble error on endpoint\n");
+               status = -EOVERFLOW;
+               break;
        case COMP_DB_ERR:
                xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n");
                status = -ENOSR;
@@ -874,15 +941,26 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                if (event_trb != ep_ring->dequeue) {
                        /* The event was for the status stage */
                        if (event_trb == td->last_trb) {
-                               td->urb->actual_length =
-                                       td->urb->transfer_buffer_length;
+                               if (td->urb->actual_length != 0) {
+                                       /* Don't overwrite a previously set error code */
+                                       if (status == -EINPROGRESS || status == 0)
+                                               /* Did we already see a short data stage? */
+                                               status = -EREMOTEIO;
+                               } else {
+                                       td->urb->actual_length =
+                                               td->urb->transfer_buffer_length;
+                               }
                        } else {
                        /* Maybe the event was for the data stage? */
-                               if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
+                               if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {
                                        /* We didn't stop on a link TRB in the middle */
                                        td->urb->actual_length =
                                                td->urb->transfer_buffer_length -
                                                TRB_LEN(event->transfer_len);
+                                       xhci_dbg(xhci, "Waiting for status stage event\n");
+                                       urb = NULL;
+                                       goto cleanup;
+                               }
                        }
                }
        } else {
@@ -929,16 +1007,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                                        TRB_LEN(event->transfer_len));
                                        td->urb->actual_length = 0;
                                }
-                               if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
-                                       status = -EREMOTEIO;
-                               else
-                                       status = 0;
+                               /* Don't overwrite a previously set error code */
+                               if (status == -EINPROGRESS) {
+                                       if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+                                               status = -EREMOTEIO;
+                                       else
+                                               status = 0;
+                               }
                        } else {
                                td->urb->actual_length = td->urb->transfer_buffer_length;
                                /* Ignore a short packet completion if the
                                 * untransferred length was zero.
                                 */
-                               status = 0;
+                               if (status == -EREMOTEIO)
+                                       status = 0;
                        }
                } else {
                        /* Slow path - walk the list, starting from the dequeue
@@ -965,19 +1047,30 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                        TRB_LEN(event->transfer_len);
                }
        }
-       /* The Endpoint Stop Command completion will take care of
-        * any stopped TDs.  A stopped TD may be restarted, so don't update the
-        * ring dequeue pointer or take this TD off any lists yet.
-        */
        if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||
                        GET_COMP_CODE(event->transfer_len) == COMP_STOP) {
+               /* The Endpoint Stop Command completion will take care of any
+                * stopped TDs.  A stopped TD may be restarted, so don't update
+                * the ring dequeue pointer or take this TD off any lists yet.
+                */
                ep_ring->stopped_td = td;
                ep_ring->stopped_trb = event_trb;
        } else {
-               /* Update ring dequeue pointer */
-               while (ep_ring->dequeue != td->last_trb)
+               if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) {
+                       /* The transfer is completed from the driver's
+                        * perspective, but we need to issue a set dequeue
+                        * command for this stalled endpoint to move the dequeue
+                        * pointer past the TD.  We can't do that here because
+                        * the halt condition must be cleared first.
+                        */
+                       ep_ring->stopped_td = td;
+                       ep_ring->stopped_trb = event_trb;
+               } else {
+                       /* Update ring dequeue pointer */
+                       while (ep_ring->dequeue != td->last_trb)
+                               inc_deq(xhci, ep_ring, false);
                        inc_deq(xhci, ep_ring, false);
-               inc_deq(xhci, ep_ring, false);
+               }
 
                /* Clean up the endpoint's TD list */
                urb = td->urb;
@@ -987,7 +1080,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        list_del(&td->cancelled_td_list);
                        ep_ring->cancels_pending--;
                }
-               kfree(td);
+               /* Leave the TD around for the reset endpoint function to use */
+               if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) {
+                       kfree(td);
+               }
                urb->hcpriv = NULL;
        }
 cleanup:
@@ -997,6 +1093,8 @@ cleanup:
        /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
        if (urb) {
                usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
+               xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
+                               urb, td->urb->actual_length, status);
                spin_unlock(&xhci->lock);
                usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
                spin_lock(&xhci->lock);
@@ -1014,6 +1112,7 @@ void xhci_handle_event(struct xhci_hcd *xhci)
        int update_ptrs = 1;
        int ret;
 
+       xhci_dbg(xhci, "In %s\n", __func__);
        if (!xhci->event_ring || !xhci->event_ring->dequeue) {
                xhci->error_bitmask |= 1 << 1;
                return;
@@ -1026,18 +1125,25 @@ void xhci_handle_event(struct xhci_hcd *xhci)
                xhci->error_bitmask |= 1 << 2;
                return;
        }
+       xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
 
        /* FIXME: Handle more event types. */
        switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {
        case TRB_TYPE(TRB_COMPLETION):
+               xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);
                handle_cmd_completion(xhci, &event->event_cmd);
+               xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__);
                break;
        case TRB_TYPE(TRB_PORT_STATUS):
+               xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);
                handle_port_status(xhci, event);
+               xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);
                update_ptrs = 0;
                break;
        case TRB_TYPE(TRB_TRANSFER):
+               xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);
                ret = handle_tx_event(xhci, &event->trans_event);
+               xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__);
                if (ret < 0)
                        xhci->error_bitmask |= 1 << 9;
                else
@@ -1093,13 +1199,13 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                 */
                xhci_warn(xhci, "WARN urb submitted to disabled ep\n");
                return -ENOENT;
-       case EP_STATE_HALTED:
        case EP_STATE_ERROR:
-               xhci_warn(xhci, "WARN waiting for halt or error on ep "
-                               "to be cleared\n");
+               xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n");
                /* FIXME event handling code for error needs to clear it */
                /* XXX not sure if this should be -ENOENT or not */
                return -EINVAL;
+       case EP_STATE_HALTED:
+               xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");
        case EP_STATE_STOPPED:
        case EP_STATE_RUNNING:
                break;
@@ -1128,9 +1234,9 @@ static int prepare_transfer(struct xhci_hcd *xhci,
                gfp_t mem_flags)
 {
        int ret;
-
+       struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
        ret = prepare_ring(xhci, xdev->ep_rings[ep_index],
-                       xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK,
+                       ep_ctx->ep_info & EP_STATE_MASK,
                        num_trbs, mem_flags);
        if (ret)
                return ret;
@@ -1285,6 +1391,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* Queue the first TRB, even if it's zero-length */
        do {
                u32 field = 0;
+               u32 length_field = 0;
 
                /* Don't change the cycle bit of the first TRB until later */
                if (first_trb)
@@ -1314,10 +1421,13 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                        (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
                                        (unsigned int) addr + trb_buff_len);
                }
+               length_field = TRB_LEN(trb_buff_len) |
+                       TD_REMAINDER(urb->transfer_buffer_length - running_total) |
+                       TRB_INTR_TARGET(0);
                queue_trb(xhci, ep_ring, false,
-                               (u32) addr,
-                               (u32) ((u64) addr >> 32),
-                               TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+                               lower_32_bits(addr),
+                               upper_32_bits(addr),
+                               length_field,
                                /* We always want to know if the TRB was short,
                                 * or we won't get an event when it completes.
                                 * (Unless we use event data TRBs, which are a
@@ -1365,7 +1475,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        struct xhci_generic_trb *start_trb;
        bool first_trb;
        int start_cycle;
-       u32 field;
+       u32 field, length_field;
 
        int running_total, trb_buff_len, ret;
        u64 addr;
@@ -1443,10 +1553,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        td->last_trb = ep_ring->enqueue;
                        field |= TRB_IOC;
                }
+               length_field = TRB_LEN(trb_buff_len) |
+                       TD_REMAINDER(urb->transfer_buffer_length - running_total) |
+                       TRB_INTR_TARGET(0);
                queue_trb(xhci, ep_ring, false,
-                               (u32) addr,
-                               (u32) ((u64) addr >> 32),
-                               TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+                               lower_32_bits(addr),
+                               upper_32_bits(addr),
+                               length_field,
                                /* We always want to know if the TRB was short,
                                 * or we won't get an event when it completes.
                                 * (Unless we use event data TRBs, which are a
@@ -1478,7 +1591,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        struct usb_ctrlrequest *setup;
        struct xhci_generic_trb *start_trb;
        int start_cycle;
-       u32 field;
+       u32 field, length_field;
        struct xhci_td *td;
 
        ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
@@ -1528,13 +1641,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        /* If there's data, queue data TRBs */
        field = 0;
+       length_field = TRB_LEN(urb->transfer_buffer_length) |
+               TD_REMAINDER(urb->transfer_buffer_length) |
+               TRB_INTR_TARGET(0);
        if (urb->transfer_buffer_length > 0) {
                if (setup->bRequestType & USB_DIR_IN)
                        field |= TRB_DIR_IN;
                queue_trb(xhci, ep_ring, false,
                                lower_32_bits(urb->transfer_dma),
                                upper_32_bits(urb->transfer_dma),
-                               TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0),
+                               length_field,
                                /* Event on short tx */
                                field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);
        }
@@ -1603,7 +1719,8 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)
 int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                u32 slot_id)
 {
-       return queue_command(xhci, in_ctx_ptr, 0, 0,
+       return queue_command(xhci, lower_32_bits(in_ctx_ptr),
+                       upper_32_bits(in_ctx_ptr), 0,
                        TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id));
 }
 
@@ -1611,7 +1728,8 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
 int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                u32 slot_id)
 {
-       return queue_command(xhci, in_ctx_ptr, 0, 0,
+       return queue_command(xhci, lower_32_bits(in_ctx_ptr),
+                       upper_32_bits(in_ctx_ptr), 0,
                        TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));
 }
 
@@ -1639,10 +1757,23 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
        u32 type = TRB_TYPE(TRB_SET_DEQ);
 
        addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr);
-       if (addr == 0)
+       if (addr == 0) {
                xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");
                xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n",
                                deq_seg, deq_ptr);
-       return queue_command(xhci, (u32) addr | cycle_state, 0, 0,
+               return 0;
+       }
+       return queue_command(xhci, lower_32_bits(addr) | cycle_state,
+                       upper_32_bits(addr), 0,
                        trb_slot_id | trb_ep_index | type);
 }
+
+int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index)
+{
+       u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
+       u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+       u32 type = TRB_TYPE(TRB_RESET_EP);
+
+       return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type);
+}
index 8936eeb5588b9d39a9625c2323285db4aa9dbfa9..d31d32206ba318fbf28ea23a105a0bfa81f82f92 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/usb.h>
 #include <linux/timer.h>
+#include <linux/kernel.h>
 
 #include "../core/hcd.h"
 /* Code sharing between pci-quirks and xhci hcd */
  * xHCI register interface.
  * This corresponds to the eXtensible Host Controller Interface (xHCI)
  * Revision 0.95 specification
- *
- * Registers should always be accessed with double word or quad word accesses.
- *
- * Some xHCI implementations may support 64-bit address pointers.  Registers
- * with 64-bit address pointers should be written to with dword accesses by
- * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
- * xHCI implementations that do not support 64-bit address pointers will ignore
- * the high dword, and write order is irrelevant.
  */
 
 /**
@@ -96,6 +89,7 @@ struct xhci_cap_regs {
 #define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
 /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
 /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)   (((p) >> 27) & 0x1f)
 
 /* HCSPARAMS3 - hcs_params3 - bitmasks */
 /* bits 0:7, Max U1 to U0 latency for the roothub ports */
@@ -166,10 +160,10 @@ struct xhci_op_regs {
        u32     reserved1;
        u32     reserved2;
        u32     dev_notification;
-       u32     cmd_ring[2];
+       u64     cmd_ring;
        /* rsvd: offset 0x20-2F */
        u32     reserved3[4];
-       u32     dcbaa_ptr[2];
+       u64     dcbaa_ptr;
        u32     config_reg;
        /* rsvd: offset 0x3C-3FF */
        u32     reserved4[241];
@@ -254,7 +248,7 @@ struct xhci_op_regs {
 #define CMD_RING_RUNNING       (1 << 3)
 /* bits 4:5 reserved and should be preserved */
 /* Command Ring pointer - bit mask for the lower 32 bits. */
-#define CMD_RING_ADDR_MASK     (0xffffffc0)
+#define CMD_RING_RSVD_BITS     (0x3f)
 
 /* CONFIG - Configure Register - config_reg bitmasks */
 /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
@@ -382,8 +376,8 @@ struct xhci_intr_reg {
        u32     irq_control;
        u32     erst_size;
        u32     rsvd;
-       u32     erst_base[2];
-       u32     erst_dequeue[2];
+       u64     erst_base;
+       u64     erst_dequeue;
 };
 
 /* irq_pending bitmasks */
@@ -452,6 +446,27 @@ struct xhci_doorbell_array {
 #define EPI_TO_DB(p)           (((p) + 1) & 0xff)
 
 
+/**
+ * struct xhci_container_ctx
+ * @type: Type of context.  Used to calculated offsets to contained contexts.
+ * @size: Size of the context data
+ * @bytes: The raw context data given to HW
+ * @dma: dma address of the bytes
+ *
+ * Represents either a Device or Input context.  Holds a pointer to the raw
+ * memory used for the context (bytes) and dma address of it (dma).
+ */
+struct xhci_container_ctx {
+       unsigned type;
+#define XHCI_CTX_TYPE_DEVICE  0x1
+#define XHCI_CTX_TYPE_INPUT   0x2
+
+       int size;
+
+       u8 *bytes;
+       dma_addr_t dma;
+};
+
 /**
  * struct xhci_slot_ctx
  * @dev_info:  Route string, device speed, hub info, and last valid endpoint
@@ -538,7 +553,7 @@ struct xhci_slot_ctx {
 struct xhci_ep_ctx {
        u32     ep_info;
        u32     ep_info2;
-       u32     deq[2];
+       u64     deq;
        u32     tx_info;
        /* offset 0x14 - 0x1f reserved for HC internal use */
        u32     reserved[3];
@@ -589,18 +604,16 @@ struct xhci_ep_ctx {
 
 
 /**
- * struct xhci_device_control
- * Input/Output context; see section 6.2.5.
+ * struct xhci_input_control_context
+ * Input control context; see section 6.2.5.
  *
  * @drop_context:      set the bit of the endpoint context you want to disable
  * @add_context:       set the bit of the endpoint context you want to enable
  */
-struct xhci_device_control {
+struct xhci_input_control_ctx {
        u32     drop_flags;
        u32     add_flags;
-       u32     rsvd[6];
-       struct xhci_slot_ctx    slot;
-       struct xhci_ep_ctx      ep[31];
+       u32     rsvd2[6];
 };
 
 /* drop context bitmasks */
@@ -608,7 +621,6 @@ struct xhci_device_control {
 /* add context bitmasks */
 #define        ADD_EP(x)       (0x1 << x)
 
-
 struct xhci_virt_device {
        /*
         * Commands to the hardware are passed an "input context" that
@@ -618,11 +630,10 @@ struct xhci_virt_device {
         * track of input and output contexts separately because
         * these commands might fail and we don't trust the hardware.
         */
-       struct xhci_device_control      *out_ctx;
-       dma_addr_t                      out_ctx_dma;
+       struct xhci_container_ctx       *out_ctx;
        /* Used for addressing devices and configuration changes */
-       struct xhci_device_control      *in_ctx;
-       dma_addr_t                      in_ctx_dma;
+       struct xhci_container_ctx       *in_ctx;
+
        /* FIXME when stream support is added */
        struct xhci_ring                *ep_rings[31];
        /* Temporary storage in case the configure endpoint command fails and we
@@ -641,7 +652,7 @@ struct xhci_virt_device {
  */
 struct xhci_device_context_array {
        /* 64-bit device addresses; we only write 32-bit addresses */
-       u32                     dev_context_ptrs[2*MAX_HC_SLOTS];
+       u64                     dev_context_ptrs[MAX_HC_SLOTS];
        /* private xHCD pointers */
        dma_addr_t      dma;
 };
@@ -654,7 +665,7 @@ struct xhci_device_context_array {
 
 struct xhci_stream_ctx {
        /* 64-bit stream ring address, cycle state, and stream type */
-       u32     stream_ring[2];
+       u64     stream_ring;
        /* offset 0x14 - 0x1f reserved for HC internal use */
        u32     reserved[2];
 };
@@ -662,7 +673,7 @@ struct xhci_stream_ctx {
 
 struct xhci_transfer_event {
        /* 64-bit buffer address, or immediate data */
-       u32     buffer[2];
+       u64     buffer;
        u32     transfer_len;
        /* This field is interpreted differently based on the type of TRB */
        u32     flags;
@@ -744,7 +755,7 @@ struct xhci_transfer_event {
 
 struct xhci_link_trb {
        /* 64-bit segment pointer*/
-       u32 segment_ptr[2];
+       u64 segment_ptr;
        u32 intr_target;
        u32 control;
 };
@@ -755,7 +766,7 @@ struct xhci_link_trb {
 /* Command completion event TRB */
 struct xhci_event_cmd {
        /* Pointer to command TRB, or the value passed by the event data trb */
-       u32 cmd_trb[2];
+       u64 cmd_trb;
        u32 status;
        u32 flags;
 };
@@ -848,8 +859,8 @@ union xhci_trb {
 #define TRB_CONFIG_EP          12
 /* Evaluate Context Command */
 #define TRB_EVAL_CONTEXT       13
-/* Reset Transfer Ring Command */
-#define TRB_RESET_RING         14
+/* Reset Endpoint Command */
+#define TRB_RESET_EP           14
 /* Stop Transfer Ring Command */
 #define TRB_STOP_RING          15
 /* Set Transfer Ring Dequeue Pointer Command */
@@ -929,6 +940,7 @@ struct xhci_ring {
        unsigned int            cancels_pending;
        unsigned int            state;
 #define SET_DEQ_PENDING                (1 << 0)
+#define EP_HALTED              (1 << 1)
        /* The TRB that was last reported in a stopped endpoint ring */
        union xhci_trb          *stopped_trb;
        struct xhci_td          *stopped_td;
@@ -940,9 +952,15 @@ struct xhci_ring {
        u32                     cycle_state;
 };
 
+struct xhci_dequeue_state {
+       struct xhci_segment *new_deq_seg;
+       union xhci_trb *new_deq_ptr;
+       int new_cycle_state;
+};
+
 struct xhci_erst_entry {
        /* 64-bit event ring segment address */
-       u32     seg_addr[2];
+       u64     seg_addr;
        u32     seg_size;
        /* Set to zero */
        u32     rsvd;
@@ -957,6 +975,13 @@ struct xhci_erst {
        unsigned int            erst_size;
 };
 
+struct xhci_scratchpad {
+       u64 *sp_array;
+       dma_addr_t sp_dma;
+       void **sp_buffers;
+       dma_addr_t *sp_dma_buffers;
+};
+
 /*
  * Each segment table entry is 4*32bits long.  1K seems like an ok size:
  * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
@@ -1011,6 +1036,9 @@ struct xhci_hcd {
        struct xhci_ring        *cmd_ring;
        struct xhci_ring        *event_ring;
        struct xhci_erst        erst;
+       /* Scratchpad */
+       struct xhci_scratchpad  *scratchpad;
+
        /* slot enabling and address device helpers */
        struct completion       addr_dev;
        int slot_id;
@@ -1071,13 +1099,43 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
 static inline void xhci_writel(struct xhci_hcd *xhci,
                const unsigned int val, __u32 __iomem *regs)
 {
-       if (!in_interrupt())
-               xhci_dbg(xhci,
-                        "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
-                        regs, val);
+       xhci_dbg(xhci,
+                       "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
+                       regs, val);
        writel(val, regs);
 }
 
+/*
+ * Registers should always be accessed with double word or quad word accesses.
+ *
+ * Some xHCI implementations may support 64-bit address pointers.  Registers
+ * with 64-bit address pointers should be written to with dword accesses by
+ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
+ * xHCI implementations that do not support 64-bit address pointers will ignore
+ * the high dword, and write order is irrelevant.
+ */
+static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
+               __u64 __iomem *regs)
+{
+       __u32 __iomem *ptr = (__u32 __iomem *) regs;
+       u64 val_lo = readl(ptr);
+       u64 val_hi = readl(ptr + 1);
+       return val_lo + (val_hi << 32);
+}
+static inline void xhci_write_64(struct xhci_hcd *xhci,
+               const u64 val, __u64 __iomem *regs)
+{
+       __u32 __iomem *ptr = (__u32 __iomem *) regs;
+       u32 val_lo = lower_32_bits(val);
+       u32 val_hi = upper_32_bits(val);
+
+       xhci_dbg(xhci,
+                       "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n",
+                       regs, (long unsigned int) val);
+       writel(val_lo, ptr);
+       writel(val_hi, ptr + 1);
+}
+
 /* xHCI debugging */
 void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
 void xhci_print_registers(struct xhci_hcd *xhci);
@@ -1090,7 +1148,7 @@ void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);
 void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
 void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
 void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep);
+void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
 
 /* xHCI memory managment */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
@@ -1128,6 +1186,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
 int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
 int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
 int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
+void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
 int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 
@@ -1148,10 +1207,23 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
                int slot_id, unsigned int ep_index);
 int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                u32 slot_id);
+int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index);
+void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
+               unsigned int slot_id, unsigned int ep_index,
+               struct xhci_td *cur_td, struct xhci_dequeue_state *state);
+void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
+               struct xhci_ring *ep_ring, unsigned int slot_id,
+               unsigned int ep_index, struct xhci_dequeue_state *deq_state);
 
 /* xHCI roothub code */
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
                char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
 
+/* xHCI contexts */
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+
 #endif /* __LINUX_XHCI_HCD_H */
index a68d91a11bee32422dd1296ff539b7b036228b73..abe3aa67ed0033d59a6735d9d61e3ec97529ad01 100644 (file)
@@ -220,7 +220,7 @@ config USB_IOWARRIOR
 
 config USB_TEST
        tristate "USB testing driver"
-       depends on USB && USB_DEVICEFS
+       depends on USB
        help
          This driver is for testing host controller software.  It is used
          with specialized device firmware for regression and stress testing,
index 3c5fe5cee05abab286dcc2f00d6cc1f70b031e06..90e1a8dedfa91404f8ce1ac48b159818eead87b8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/usb/iowarrior.h>
 
index deb95bb49fd195d333a77152e21fef88f2d26ae3..d645f3899fe1c52a09599e90d241006337591381 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/random.h>
 #include <linux/poll.h>
index e0ff9ccd866baff21039a6dadbb920a08e866636..29092b8e59ceb7347a2f217282d7918eaf98cfe2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
index 8a39de3e6e471c9c8f8c7b72f5b515218cb816c4..59bf949e589b85a086be064ffb037a77bedc7e24 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/dmapool.h>
 
index 180d7daa4099d50231f81f92c8ce537ab72dcbcc..e16ff605c458aa5a5b29e224deec2033adb96851 100644 (file)
 #include <mach/hardware.h>
 #include <mach/memory.h>
 #include <mach/gpio.h>
+#include <mach/cputype.h>
 
 #include <asm/mach-types.h>
 
 #include "musb_core.h"
 
 #ifdef CONFIG_MACH_DAVINCI_EVM
-#define GPIO_nVBUS_DRV         87
+#define GPIO_nVBUS_DRV         144
 #endif
 
 #include "davinci.h"
@@ -329,7 +330,6 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
                        mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
                        WARNING("VBUS error workaround (delay coming)\n");
                } else if (is_host_enabled(musb) && drvvbus) {
-                       musb->is_active = 1;
                        MUSB_HST_MODE(musb);
                        musb->xceiv->default_a = 1;
                        musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -343,7 +343,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
                        portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
                }
 
-               /* NOTE:  this must complete poweron within 100 msec */
+               /* NOTE:  this must complete poweron within 100 msec
+                * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
+                */
                davinci_source_power(musb, drvvbus, 0);
                DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
@@ -411,6 +413,21 @@ int __init musb_platform_init(struct musb *musb)
                __raw_writel(phy_ctrl, USB_PHY_CTRL);
        }
 
+       /* On dm355, the default-A state machine needs DRVVBUS control.
+        * If we won't be a host, there's no need to turn it on.
+        */
+       if (cpu_is_davinci_dm355()) {
+               u32     deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+               if (is_host_enabled(musb)) {
+                       deepsleep &= ~DRVVBUS_OVERRIDE;
+               } else {
+                       deepsleep &= ~DRVVBUS_FORCE;
+                       deepsleep |= DRVVBUS_OVERRIDE;
+               }
+               __raw_writel(deepsleep, DM355_DEEPSLEEP);
+       }
+
        /* reset the controller */
        musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
 
@@ -437,6 +454,15 @@ int musb_platform_exit(struct musb *musb)
        if (is_host_enabled(musb))
                del_timer_sync(&otg_workaround);
 
+       /* force VBUS off */
+       if (cpu_is_davinci_dm355()) {
+               u32     deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+               deepsleep &= ~DRVVBUS_FORCE;
+               deepsleep |= DRVVBUS_OVERRIDE;
+               __raw_writel(deepsleep, DM355_DEEPSLEEP);
+       }
+
        davinci_source_power(musb, 0 /*off*/, 1);
 
        /* delay, to avoid problems with module reload */
index 554a414f65d1104cbbbeeaed2885f2a209faf42d..c7c1ca0494cda359096b1eeeb281a55b80f2c994 100644 (file)
@@ -1326,7 +1326,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
        int             i;
 
        /* log core options (read using indexed model) */
-       musb_ep_select(mbase, 0);
        reg = musb_read_configdata(mbase);
 
        strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
@@ -1990,7 +1989,7 @@ bad_config:
        if (status < 0)
                goto fail2;
 
-#ifdef CONFIG_USB_OTG
+#ifdef CONFIG_USB_MUSB_OTG
        setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
 #endif
 
index f3772ca3b2cf799569389870e60a159732f5ca70..381d648a36b8122e974b0f4c5e0001611d8f0e49 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
index 40ed50ecedff6ed84a72d4342616a6f07e36f362..7a6778675ad3a8d5a76d1f8de9477a8c48309d12 100644 (file)
@@ -407,7 +407,7 @@ stall:
                                        csr |= MUSB_RXCSR_P_SENDSTALL
                                                | MUSB_RXCSR_FLUSHFIFO
                                                | MUSB_RXCSR_CLRDATATOG
-                                               | MUSB_TXCSR_P_WZC_BITS;
+                                               | MUSB_RXCSR_P_WZC_BITS;
                                        musb_writew(regs, MUSB_RXCSR,
                                                        csr);
                                }
index 94a2a350a4141521e9e4d93426700ed3a31aaf6b..cf94511485f258a07d60186d43e3687fcf959a87 100644 (file)
@@ -373,7 +373,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
                musb_save_toggle(qh, is_in, urb);
                break;
        case USB_ENDPOINT_XFER_ISOC:
-               if (urb->error_count)
+               if (status == 0 && urb->error_count)
                        status = -EXDEV;
                break;
        }
@@ -2235,13 +2235,30 @@ static void musb_h_stop(struct usb_hcd *hcd)
 static int musb_bus_suspend(struct usb_hcd *hcd)
 {
        struct musb     *musb = hcd_to_musb(hcd);
+       u8              devctl;
 
-       if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
+       if (!is_host_active(musb))
                return 0;
 
-       if (is_host_active(musb) && musb->is_active) {
-               WARNING("trying to suspend as %s is_active=%i\n",
-                       otg_state_string(musb), musb->is_active);
+       switch (musb->xceiv->state) {
+       case OTG_STATE_A_SUSPEND:
+               return 0;
+       case OTG_STATE_A_WAIT_VRISE:
+               /* ID could be grounded even if there's no device
+                * on the other end of the cable.  NOTE that the
+                * A_WAIT_VRISE timers are messy with MUSB...
+                */
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+                       musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               break;
+       default:
+               break;
+       }
+
+       if (musb->is_active) {
+               WARNING("trying to suspend as %s while active\n",
+                               otg_state_string(musb));
                return -EBUSY;
        } else
                return 0;
index de3b2f18db4469943b0e7ce3b437ff98d53e0022..fbfd3fd9ce1f876f4949b15b1de016e7877d1348 100644 (file)
@@ -323,6 +323,7 @@ static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
 
 static inline u8 musb_read_configdata(void __iomem *mbase)
 {
+       musb_writeb(mbase, MUSB_INDEX, 0);
        return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
 }
 
index 69feeec1628ce28bd8744ef5c6048d0b7a12746c..aa884d072f0b4c7202e5b421e52b0ca37a5163de 100644 (file)
@@ -59,18 +59,4 @@ config NOP_USB_XCEIV
         built-in with usb ip or which are autonomous and doesn't require any
         phy programming such as ISP1x04 etc.
 
-config USB_LANGWELL_OTG
-       tristate "Intel Langwell USB OTG dual-role support"
-       depends on USB && MRST
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Say Y here if you want to build Intel Langwell USB OTG
-         transciever driver in kernel. This driver implements role
-         switch between EHCI host driver and Langwell USB OTG
-         client driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called langwell_otg.
-
 endif # USB || OTG
index 6d1abdd3c0ac9cc1a2cd688dd9fda768ee2562a1..208167856529f26225807cd7edea4fb29a3640e9 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_USB_OTG_UTILS)     += otg.o
 obj-$(CONFIG_USB_GPIO_VBUS)    += gpio_vbus.o
 obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
 obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
-obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
 obj-$(CONFIG_NOP_USB_XCEIV)    += nop-usb-xceiv.o
 
 ccflags-$(CONFIG_USB_DEBUG)    += -DDEBUG
diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c
deleted file mode 100644 (file)
index 6f628d0..0000000
+++ /dev/null
@@ -1,1915 +0,0 @@
-/*
- * Intel Langwell USB OTG transceiver driver
- * Copyright (C) 2008 - 2009, 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.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-/* This driver helps to switch Langwell OTG controller function between host
- * and peripheral. It works with EHCI driver and Langwell client controller
- * driver together.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb.h>
-#include <linux/usb/otg.h>
-#include <linux/notifier.h>
-#include <asm/ipc_defs.h>
-#include <linux/delay.h>
-#include "../core/hcd.h"
-
-#include <linux/usb/langwell_otg.h>
-
-#define        DRIVER_DESC             "Intel Langwell USB OTG transceiver driver"
-#define        DRIVER_VERSION          "3.0.0.32L.0002"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
-static const char driver_name[] = "langwell_otg";
-
-static int langwell_otg_probe(struct pci_dev *pdev,
-                       const struct pci_device_id *id);
-static void langwell_otg_remove(struct pci_dev *pdev);
-static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message);
-static int langwell_otg_resume(struct pci_dev *pdev);
-
-static int langwell_otg_set_host(struct otg_transceiver *otg,
-                               struct usb_bus *host);
-static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
-                               struct usb_gadget *gadget);
-static int langwell_otg_start_srp(struct otg_transceiver *otg);
-
-static const struct pci_device_id pci_ids[] = {{
-       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-       .class_mask =   ~0,
-       .vendor =       0x8086,
-       .device =       0x0811,
-       .subvendor =    PCI_ANY_ID,
-       .subdevice =    PCI_ANY_ID,
-}, { /* end: all zeroes */ }
-};
-
-static struct pci_driver otg_pci_driver = {
-       .name =         (char *) driver_name,
-       .id_table =     pci_ids,
-
-       .probe =        langwell_otg_probe,
-       .remove =       langwell_otg_remove,
-
-       .suspend =      langwell_otg_suspend,
-       .resume =       langwell_otg_resume,
-};
-
-static const char *state_string(enum usb_otg_state state)
-{
-       switch (state) {
-       case OTG_STATE_A_IDLE:
-               return "a_idle";
-       case OTG_STATE_A_WAIT_VRISE:
-               return "a_wait_vrise";
-       case OTG_STATE_A_WAIT_BCON:
-               return "a_wait_bcon";
-       case OTG_STATE_A_HOST:
-               return "a_host";
-       case OTG_STATE_A_SUSPEND:
-               return "a_suspend";
-       case OTG_STATE_A_PERIPHERAL:
-               return "a_peripheral";
-       case OTG_STATE_A_WAIT_VFALL:
-               return "a_wait_vfall";
-       case OTG_STATE_A_VBUS_ERR:
-               return "a_vbus_err";
-       case OTG_STATE_B_IDLE:
-               return "b_idle";
-       case OTG_STATE_B_SRP_INIT:
-               return "b_srp_init";
-       case OTG_STATE_B_PERIPHERAL:
-               return "b_peripheral";
-       case OTG_STATE_B_WAIT_ACON:
-               return "b_wait_acon";
-       case OTG_STATE_B_HOST:
-               return "b_host";
-       default:
-               return "UNDEFINED";
-       }
-}
-
-/* HSM timers */
-static inline struct langwell_otg_timer *otg_timer_initializer
-(void (*function)(unsigned long), unsigned long expires, unsigned long data)
-{
-       struct langwell_otg_timer *timer;
-       timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL);
-       timer->function = function;
-       timer->expires = expires;
-       timer->data = data;
-       return timer;
-}
-
-static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
-       *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr,
-       *b_bus_suspend_tmr;
-
-static struct list_head active_timers;
-
-static struct langwell_otg *the_transceiver;
-
-/* host/client notify transceiver when event affects HNP state */
-void langwell_update_transceiver()
-{
-       otg_dbg("transceiver driver is notified\n");
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-}
-EXPORT_SYMBOL(langwell_update_transceiver);
-
-static int langwell_otg_set_host(struct otg_transceiver *otg,
-                                       struct usb_bus *host)
-{
-       otg->host = host;
-
-       return 0;
-}
-
-static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
-                                       struct usb_gadget *gadget)
-{
-       otg->gadget = gadget;
-
-       return 0;
-}
-
-static int langwell_otg_set_power(struct otg_transceiver *otg,
-                               unsigned mA)
-{
-       return 0;
-}
-
-/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/
-static void langwell_otg_drv_vbus(int on)
-{
-       struct ipc_pmic_reg_data        pmic_data = {0};
-       struct ipc_pmic_reg_data        battery_data;
-
-       /* Check if battery is attached or not */
-       battery_data.pmic_reg_data[0].register_address = 0xd2;
-       battery_data.ioc = 0;
-       battery_data.num_entries = 1;
-       if (ipc_pmic_register_read(&battery_data)) {
-               otg_dbg("Failed to read PMIC register 0xd2.\n");
-               return;
-       }
-
-       if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) {
-               otg_dbg("no battery attached\n");
-               return;
-       }
-
-       /* Workaround for battery attachment issue */
-       if (battery_data.pmic_reg_data[0].value == 0x34) {
-               otg_dbg("battery \n");
-               return;
-       }
-
-       otg_dbg("battery attached\n");
-
-       pmic_data.ioc = 0;
-       pmic_data.pmic_reg_data[0].register_address = 0xD4;
-       pmic_data.num_entries = 1;
-       if (on)
-               pmic_data.pmic_reg_data[0].value = 0x20;
-       else
-               pmic_data.pmic_reg_data[0].value = 0xc0;
-
-       if (ipc_pmic_register_write(&pmic_data, TRUE))
-               otg_dbg("Failed to write PMIC.\n");
-
-}
-
-/* charge vbus or discharge vbus through a resistor to ground */
-static void langwell_otg_chrg_vbus(int on)
-{
-
-       u32     val;
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD,
-                               the_transceiver->regs + CI_OTGSC);
-
-}
-
-/* Start SRP */
-static int langwell_otg_start_srp(struct otg_transceiver *otg)
-{
-       u32     val;
-
-       otg_dbg("Start SRP ->\n");
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-
-       writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
-               the_transceiver->regs + CI_OTGSC);
-
-       /* Check if the data plus is finished or not */
-       msleep(8);
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (val & (OTGSC_HADP | OTGSC_DP))
-               otg_dbg("DataLine SRP Error\n");
-
-       /* FIXME: VBus SRP */
-
-       return 0;
-}
-
-
-/* stop SOF via bus_suspend */
-static void langwell_otg_loc_sof(int on)
-{
-       struct usb_hcd  *hcd;
-       int             err;
-
-       otg_dbg("loc_sof -> %d\n", on);
-
-       hcd = bus_to_hcd(the_transceiver->otg.host);
-       if (on)
-               err = hcd->driver->bus_resume(hcd);
-       else
-               err = hcd->driver->bus_suspend(hcd);
-
-       if (err)
-               otg_dbg("Failed to resume/suspend bus - %d\n", err);
-}
-
-static void langwell_otg_phy_low_power(int on)
-{
-       u32     val;
-
-       otg_dbg("phy low power mode-> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_HOSTPC1);
-       if (on)
-               writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
-       else
-               writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
-}
-
-/* Enable/Disable OTG interrupt */
-static void langwell_otg_intr(int on)
-{
-       u32 val;
-
-       otg_dbg("interrupt -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on) {
-               val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU);
-               writel(val, the_transceiver->regs + CI_OTGSC);
-       } else {
-               val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU);
-               writel(val, the_transceiver->regs + CI_OTGSC);
-       }
-}
-
-/* set HAAR: Hardware Assist Auto-Reset */
-static void langwell_otg_HAAR(int on)
-{
-       u32     val;
-
-       otg_dbg("HAAR -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR,
-                               the_transceiver->regs + CI_OTGSC);
-}
-
-/* set HABA: Hardware Assist B-Disconnect to A-Connect */
-static void langwell_otg_HABA(int on)
-{
-       u32     val;
-
-       otg_dbg("HABA -> %d\n", on);
-
-       val = readl(the_transceiver->regs + CI_OTGSC);
-       if (on)
-               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
-                               the_transceiver->regs + CI_OTGSC);
-       else
-               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
-                               the_transceiver->regs + CI_OTGSC);
-}
-
-static int langwell_otg_check_se0_srp(int on)
-{
-       u32 val;
-
-       int delay_time = TB_SE0_SRP * 10; /* step is 100us */
-
-       otg_dbg("check_se0_srp -> \n");
-
-       do {
-               udelay(100);
-               if (!delay_time--)
-                       break;
-               val = readl(the_transceiver->regs + CI_PORTSC1);
-               val &= PORTSC_LS;
-       } while (!val);
-
-       otg_dbg("check_se0_srp <- \n");
-       return val;
-}
-
-/* The timeout callback function to set time out bit */
-static void set_tmout(unsigned long indicator)
-{
-       *(int *)indicator = 1;
-}
-
-void langwell_otg_nsf_msg(unsigned long indicator)
-{
-       switch (indicator) {
-       case 2:
-       case 4:
-       case 6:
-       case 7:
-               printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n",
-                               indicator);
-               break;
-       case 3:
-               printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n",
-                               indicator);
-               break;
-       default:
-               printk(KERN_ERR "Do not have this kind of NSF\n");
-               break;
-       }
-}
-
-/* Initialize timers */
-static void langwell_otg_init_timers(struct otg_hsm *hsm)
-{
-       /* HSM used timers */
-       a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
-                               (unsigned long)&hsm->a_wait_vrise_tmout);
-       a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
-                               (unsigned long)&hsm->a_wait_bcon_tmout);
-       a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
-                               (unsigned long)&hsm->a_aidl_bdis_tmout);
-       b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
-                               (unsigned long)&hsm->b_ase0_brst_tmout);
-       b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
-                               (unsigned long)&hsm->b_se0_srp);
-       b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES,
-                               (unsigned long)&hsm->b_srp_res_tmout);
-       b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND,
-                               (unsigned long)&hsm->b_bus_suspend_tmout);
-}
-
-/* Free timers */
-static void langwell_otg_free_timers(void)
-{
-       kfree(a_wait_vrise_tmr);
-       kfree(a_wait_bcon_tmr);
-       kfree(a_aidl_bdis_tmr);
-       kfree(b_ase0_brst_tmr);
-       kfree(b_se0_srp_tmr);
-       kfree(b_srp_res_tmr);
-       kfree(b_bus_suspend_tmr);
-}
-
-/* Add timer to timer list */
-static void langwell_otg_add_timer(void *gtimer)
-{
-       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
-       struct langwell_otg_timer *tmp_timer;
-       u32     val32;
-
-       /* Check if the timer is already in the active list,
-        * if so update timer count
-        */
-       list_for_each_entry(tmp_timer, &active_timers, list)
-               if (tmp_timer == timer) {
-                       timer->count = timer->expires;
-                       return;
-               }
-       timer->count = timer->expires;
-
-       if (list_empty(&active_timers)) {
-               val32 = readl(the_transceiver->regs + CI_OTGSC);
-               writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
-       }
-
-       list_add_tail(&timer->list, &active_timers);
-}
-
-/* Remove timer from the timer list; clear timeout status */
-static void langwell_otg_del_timer(void *gtimer)
-{
-       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
-       struct langwell_otg_timer *tmp_timer, *del_tmp;
-       u32 val32;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
-               if (tmp_timer == timer)
-                       list_del(&timer->list);
-
-       if (list_empty(&active_timers)) {
-               val32 = readl(the_transceiver->regs + CI_OTGSC);
-               writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
-       }
-}
-
-/* Reduce timer count by 1, and find timeout conditions.*/
-static int langwell_otg_tick_timer(u32 *int_sts)
-{
-       struct langwell_otg_timer *tmp_timer, *del_tmp;
-       int expired = 0;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
-               tmp_timer->count--;
-               /* check if timer expires */
-               if (!tmp_timer->count) {
-                       list_del(&tmp_timer->list);
-                       tmp_timer->function(tmp_timer->data);
-                       expired = 1;
-               }
-       }
-
-       if (list_empty(&active_timers)) {
-               otg_dbg("tick timer: disable 1ms int\n");
-               *int_sts = *int_sts & ~OTGSC_1MSE;
-       }
-       return expired;
-}
-
-static void reset_otg(void)
-{
-       u32     val;
-       int     delay_time = 1000;
-
-       otg_dbg("reseting OTG controller ...\n");
-       val = readl(the_transceiver->regs + CI_USBCMD);
-       writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD);
-       do {
-               udelay(100);
-               if (!delay_time--)
-                       otg_dbg("reset timeout\n");
-               val = readl(the_transceiver->regs + CI_USBCMD);
-               val &= USBCMD_RST;
-       } while (val != 0);
-       otg_dbg("reset done.\n");
-}
-
-static void set_host_mode(void)
-{
-       u32     val;
-
-       reset_otg();
-       val = readl(the_transceiver->regs + CI_USBMODE);
-       val = (val & (~USBMODE_CM)) | USBMODE_HOST;
-       writel(val, the_transceiver->regs + CI_USBMODE);
-}
-
-static void set_client_mode(void)
-{
-       u32     val;
-
-       reset_otg();
-       val = readl(the_transceiver->regs + CI_USBMODE);
-       val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
-       writel(val, the_transceiver->regs + CI_USBMODE);
-}
-
-static void init_hsm(void)
-{
-       struct langwell_otg     *langwell = the_transceiver;
-       u32                     val32;
-
-       /* read OTGSC after reset */
-       val32 = readl(langwell->regs + CI_OTGSC);
-       otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32);
-
-       /* set init state */
-       if (val32 & OTGSC_ID) {
-               langwell->hsm.id = 1;
-               langwell->otg.default_a = 0;
-               set_client_mode();
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               langwell_otg_drv_vbus(0);
-       } else {
-               langwell->hsm.id = 0;
-               langwell->otg.default_a = 1;
-               set_host_mode();
-               langwell->otg.state = OTG_STATE_A_IDLE;
-       }
-
-       /* set session indicator */
-       if (val32 & OTGSC_BSE)
-               langwell->hsm.b_sess_end = 1;
-       if (val32 & OTGSC_BSV)
-               langwell->hsm.b_sess_vld = 1;
-       if (val32 & OTGSC_ASV)
-               langwell->hsm.a_sess_vld = 1;
-       if (val32 & OTGSC_AVV)
-               langwell->hsm.a_vbus_vld = 1;
-
-       /* defautly power the bus */
-       langwell->hsm.a_bus_req = 1;
-       langwell->hsm.a_bus_drop = 0;
-       /* defautly don't request bus as B device */
-       langwell->hsm.b_bus_req = 0;
-       /* no system error */
-       langwell->hsm.a_clr_err = 0;
-}
-
-static irqreturn_t otg_dummy_irq(int irq, void *_dev)
-{
-       void __iomem    *reg_base = _dev;
-       u32     val;
-       u32     int_mask = 0;
-
-       val = readl(reg_base + CI_USBMODE);
-       if ((val & USBMODE_CM) != USBMODE_DEVICE)
-               return IRQ_NONE;
-
-       val = readl(reg_base + CI_USBSTS);
-       int_mask = val & INTR_DUMMY_MASK;
-
-       if (int_mask == 0)
-               return IRQ_NONE;
-
-       /* clear hsm.b_conn here since host driver can't detect it
-       *  otg_dummy_irq called means B-disconnect happened.
-       */
-       if (the_transceiver->hsm.b_conn) {
-               the_transceiver->hsm.b_conn = 0;
-               if (spin_trylock(&the_transceiver->wq_lock)) {
-                       queue_work(the_transceiver->qwork,
-                               &the_transceiver->work);
-                       spin_unlock(&the_transceiver->wq_lock);
-               }
-       }
-       /* Clear interrupts */
-       writel(int_mask, reg_base + CI_USBSTS);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t otg_irq(int irq, void *_dev)
-{
-       struct  langwell_otg *langwell = _dev;
-       u32     int_sts, int_en;
-       u32     int_mask = 0;
-       int     flag = 0;
-
-       int_sts = readl(langwell->regs + CI_OTGSC);
-       int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
-       int_mask = int_sts & int_en;
-       if (int_mask == 0)
-               return IRQ_NONE;
-
-       if (int_mask & OTGSC_IDIS) {
-               otg_dbg("%s: id change int\n", __func__);
-               langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_DPIS) {
-               otg_dbg("%s: data pulse int\n", __func__);
-               langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_BSEIS) {
-               otg_dbg("%s: b session end int\n", __func__);
-               langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_BSVIS) {
-               otg_dbg("%s: b session valid int\n", __func__);
-               langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_ASVIS) {
-               otg_dbg("%s: a session valid int\n", __func__);
-               langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
-               flag = 1;
-       }
-       if (int_mask & OTGSC_AVVIS) {
-               otg_dbg("%s: a vbus valid int\n", __func__);
-               langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
-               flag = 1;
-       }
-
-       if (int_mask & OTGSC_1MSS) {
-               /* need to schedule otg_work if any timer is expired */
-               if (langwell_otg_tick_timer(&int_sts))
-                       flag = 1;
-       }
-
-       writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
-                       langwell->regs + CI_OTGSC);
-       if (flag)
-               queue_work(langwell->qwork, &langwell->work);
-
-       return IRQ_HANDLED;
-}
-
-static void langwell_otg_work(struct work_struct *work)
-{
-       struct langwell_otg *langwell = container_of(work,
-                                       struct langwell_otg, work);
-       int     retval;
-
-       otg_dbg("%s: old state = %s\n", __func__,
-                       state_string(langwell->otg.state));
-
-       switch (langwell->otg.state) {
-       case OTG_STATE_UNDEFINED:
-       case OTG_STATE_B_IDLE:
-               if (!langwell->hsm.id) {
-                       langwell_otg_del_timer(b_srp_res_tmr);
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_chrg_vbus(0);
-                       langwell_otg_drv_vbus(0);
-
-                       set_host_mode();
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.b_srp_res_tmout) {
-                       langwell->hsm.b_srp_res_tmout = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_nsf_msg(6);
-               } else if (langwell->hsm.b_sess_vld) {
-                       langwell_otg_del_timer(b_srp_res_tmr);
-                       langwell->hsm.b_sess_end = 0;
-                       langwell->hsm.a_bus_suspend = 0;
-
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->client_ops) {
-                               langwell->client_ops->resume(langwell->pdev);
-                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-                       } else
-                               otg_dbg("client driver not loaded.\n");
-
-               } else if (langwell->hsm.b_bus_req &&
-                               (langwell->hsm.b_sess_end)) {
-                       /* workaround for b_se0_srp detection */
-                       retval = langwell_otg_check_se0_srp(0);
-                       if (retval) {
-                               langwell->hsm.b_bus_req = 0;
-                               otg_dbg("LS is not SE0, try again later\n");
-                       } else {
-                               /* Start SRP */
-                               langwell_otg_start_srp(&langwell->otg);
-                               langwell_otg_add_timer(b_srp_res_tmr);
-                       }
-               }
-               break;
-       case OTG_STATE_B_SRP_INIT:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.b_sess_vld) {
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->client_ops) {
-                               langwell->client_ops->resume(langwell->pdev);
-                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-                       } else
-                               otg_dbg("client driver not loaded.\n");
-               }
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell->hsm.b_hnp_enable = 0;
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable
-                       && langwell->hsm.a_bus_suspend) {
-
-                       if (langwell->client_ops) {
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       } else
-                               otg_dbg("client driver has been removed.\n");
-
-                       langwell_otg_HAAR(1);
-                       langwell->hsm.a_conn = 0;
-
-                       if (langwell->host_ops) {
-                               langwell->host_ops->probe(langwell->pdev,
-                                       langwell->host_ops->id_table);
-                               langwell->otg.state = OTG_STATE_B_WAIT_ACON;
-                       } else
-                               otg_dbg("host driver not loaded.\n");
-
-                       langwell->hsm.a_bus_resume = 0;
-                       langwell->hsm.b_ase0_brst_tmout = 0;
-                       langwell_otg_add_timer(b_ase0_brst_tmr);
-               }
-               break;
-
-       case OTG_STATE_B_WAIT_ACON:
-               if (!langwell->hsm.id) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-
-                       langwell_otg_HAAR(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell->hsm.b_hnp_enable = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_chrg_vbus(0);
-                       langwell_otg_HAAR(0);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.a_conn) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell_otg_HAAR(0);
-                       langwell->otg.state = OTG_STATE_B_HOST;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_resume ||
-                               langwell->hsm.b_ase0_brst_tmout) {
-                       langwell_otg_del_timer(b_ase0_brst_tmr);
-                       langwell_otg_HAAR(0);
-                       langwell_otg_nsf_msg(7);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.a_bus_suspend = 0;
-                       langwell->hsm.b_bus_req = 0;
-
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-               }
-               break;
-
-       case OTG_STATE_B_HOST:
-               if (!langwell->hsm.id) {
-                       langwell->otg.default_a = 1;
-                       langwell->hsm.a_srp_det = 0;
-
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-                       set_host_mode();
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.b_sess_vld) {
-                       langwell->hsm.b_hnp_enable = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_chrg_vbus(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if ((!langwell->hsm.b_bus_req) ||
-                               (!langwell->hsm.a_conn)) {
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_loc_sof(0);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.a_bus_suspend = 0;
-
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
-               }
-               break;
-
-       case OTG_STATE_A_IDLE:
-               langwell->otg.default_a = 1;
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       langwell_otg_drv_vbus(0);
-                       langwell_otg_chrg_vbus(0);
-
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_sess_vld) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_srp_det = 1;
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_bus_drop &&
-                       (langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-                       queue_work(langwell->qwork, &langwell->work);
-               }
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_wait_vrise_tmr);
-                       langwell->hsm.b_bus_req = 0;
-                       langwell->otg.default_a = 0;
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-               } else if (langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_wait_vrise_tmr);
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.b_conn = 0;
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               } else if (langwell->hsm.a_wait_vrise_tmout) {
-                       if (langwell->hsm.a_vbus_vld) {
-                               if (langwell->host_ops)
-                                       langwell->host_ops->probe(
-                                               langwell->pdev,
-                                               langwell->host_ops->id_table);
-                               else
-                                       otg_dbg("host driver not loaded.\n");
-                               langwell->hsm.b_conn = 0;
-                               langwell->hsm.a_set_b_hnp_en = 0;
-                               langwell->hsm.a_wait_bcon_tmout = 0;
-                               langwell_otg_add_timer(a_wait_bcon_tmr);
-                               langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-                       } else {
-                               langwell_otg_drv_vbus(0);
-                               langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-                       }
-               }
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_bus_drop ||
-                               (langwell->hsm.a_wait_bcon_tmout &&
-                               !langwell->hsm.a_bus_req)) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (langwell->hsm.b_conn) {
-                       langwell_otg_del_timer(a_wait_bcon_tmr);
-
-                       langwell->hsm.a_suspend_req = 0;
-                       langwell->otg.state = OTG_STATE_A_HOST;
-                       if (!langwell->hsm.a_bus_req &&
-                               langwell->hsm.a_set_b_hnp_en) {
-                               /* It is not safe enough to do a fast
-                                * transistion from A_WAIT_BCON to
-                                * A_SUSPEND */
-                               msleep(10000);
-                               if (langwell->hsm.a_bus_req)
-                                       break;
-
-                               if (request_irq(langwell->pdev->irq,
-                                       otg_dummy_irq, IRQF_SHARED,
-                                       driver_name, langwell->regs) != 0) {
-                                       otg_dbg("request interrupt %d fail\n",
-                                       langwell->pdev->irq);
-                               }
-
-                               langwell_otg_HABA(1);
-                               langwell->hsm.b_bus_resume = 0;
-                               langwell->hsm.a_aidl_bdis_tmout = 0;
-                               langwell_otg_add_timer(a_aidl_bdis_tmr);
-
-                               langwell_otg_loc_sof(0);
-                               langwell->otg.state = OTG_STATE_A_SUSPEND;
-                       } else if (!langwell->hsm.a_bus_req &&
-                               !langwell->hsm.a_set_b_hnp_en) {
-                               struct pci_dev *pdev = langwell->pdev;
-                               if (langwell->host_ops)
-                                       langwell->host_ops->remove(pdev);
-                               else
-                                       otg_dbg("host driver removed.\n");
-                               langwell_otg_drv_vbus(0);
-                               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-                       }
-               }
-               break;
-       case OTG_STATE_A_HOST:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_drop ||
-               (!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) {
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_set_b_hnp_en
-                               && !langwell->hsm.a_bus_req) {
-                       /* Set HABA to enable hardware assistance to signal
-                        *  A-connect after receiver B-disconnect. Hardware
-                        *  will then set client mode and enable URE, SLE and
-                        *  PCE after the assistance. otg_dummy_irq is used to
-                        *  clean these ints when client driver is not resumed.
-                        */
-                       if (request_irq(langwell->pdev->irq,
-                               otg_dummy_irq, IRQF_SHARED, driver_name,
-                               langwell->regs) != 0) {
-                               otg_dbg("request interrupt %d failed\n",
-                                               langwell->pdev->irq);
-                       }
-
-                       /* set HABA */
-                       langwell_otg_HABA(1);
-                       langwell->hsm.b_bus_resume = 0;
-                       langwell->hsm.a_aidl_bdis_tmout = 0;
-                       langwell_otg_add_timer(a_aidl_bdis_tmr);
-                       langwell_otg_loc_sof(0);
-                       langwell->otg.state = OTG_STATE_A_SUSPEND;
-               } else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) {
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               }
-               break;
-       case OTG_STATE_A_SUSPEND:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_req ||
-                               langwell->hsm.b_bus_resume) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       langwell->hsm.a_suspend_req = 0;
-                       langwell_otg_loc_sof(1);
-                       langwell->otg.state = OTG_STATE_A_HOST;
-               } else if (langwell->hsm.a_aidl_bdis_tmout ||
-                               langwell->hsm.a_bus_drop) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (!langwell->hsm.b_conn &&
-                               langwell->hsm.a_set_b_hnp_en) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-
-                       langwell->hsm.b_bus_suspend = 0;
-                       langwell->hsm.b_bus_suspend_vld = 0;
-                       langwell->hsm.b_bus_suspend_tmout = 0;
-
-                       /* msleep(200); */
-                       if (langwell->client_ops)
-                               langwell->client_ops->resume(langwell->pdev);
-                       else
-                               otg_dbg("client driver not loaded.\n");
-
-                       langwell_otg_add_timer(b_bus_suspend_tmr);
-                       langwell->otg.state = OTG_STATE_A_PERIPHERAL;
-                       break;
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(a_aidl_bdis_tmr);
-                       langwell_otg_HABA(0);
-                       free_irq(langwell->pdev->irq, langwell->regs);
-                       if (langwell->host_ops)
-                               langwell->host_ops->remove(langwell->pdev);
-                       else
-                               otg_dbg("host driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               }
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               if (langwell->hsm.id) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.b_bus_req = 0;
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (!langwell->hsm.a_vbus_vld) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (langwell->hsm.a_bus_drop) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       langwell_otg_drv_vbus(0);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               } else if (langwell->hsm.b_bus_suspend) {
-                       langwell_otg_del_timer(b_bus_suspend_tmr);
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                       PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               } else if (langwell->hsm.b_bus_suspend_tmout) {
-                       u32     val;
-                       val = readl(langwell->regs + CI_PORTSC1);
-                       if (!(val & PORTSC_SUSP))
-                               break;
-                       if (langwell->client_ops)
-                               langwell->client_ops->suspend(langwell->pdev,
-                                               PMSG_FREEZE);
-                       else
-                               otg_dbg("client driver has been removed.\n");
-                       if (langwell->host_ops)
-                               langwell->host_ops->probe(langwell->pdev,
-                                               langwell->host_ops->id_table);
-                       else
-                               otg_dbg("host driver not loaded.\n");
-                       langwell->hsm.a_set_b_hnp_en = 0;
-                       langwell->hsm.a_wait_bcon_tmout = 0;
-                       langwell_otg_add_timer(a_wait_bcon_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
-               }
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->hsm.a_clr_err = 0;
-                       langwell->hsm.a_srp_det = 0;
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_clr_err) {
-                       langwell->hsm.a_clr_err = 0;
-                       langwell->hsm.a_srp_det = 0;
-                       reset_otg();
-                       init_hsm();
-                       if (langwell->otg.state == OTG_STATE_A_IDLE)
-                               queue_work(langwell->qwork, &langwell->work);
-               }
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               if (langwell->hsm.id) {
-                       langwell->otg.default_a = 0;
-                       langwell->otg.state = OTG_STATE_B_IDLE;
-                       queue_work(langwell->qwork, &langwell->work);
-               } else if (langwell->hsm.a_bus_req) {
-                       langwell_otg_drv_vbus(1);
-                       langwell->hsm.a_wait_vrise_tmout = 0;
-                       langwell_otg_add_timer(a_wait_vrise_tmr);
-                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
-               } else if (!langwell->hsm.a_sess_vld) {
-                       langwell->hsm.a_srp_det = 0;
-                       langwell_otg_drv_vbus(0);
-                       set_host_mode();
-                       langwell->otg.state = OTG_STATE_A_IDLE;
-               }
-               break;
-       default:
-               ;
-       }
-
-       otg_dbg("%s: new state = %s\n", __func__,
-                       state_string(langwell->otg.state));
-}
-
-       static ssize_t
-show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell = the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size,
-               "\n"
-               "USBCMD = 0x%08x \n"
-               "USBSTS = 0x%08x \n"
-               "USBINTR = 0x%08x \n"
-               "ASYNCLISTADDR = 0x%08x \n"
-               "PORTSC1 = 0x%08x \n"
-               "HOSTPC1 = 0x%08x \n"
-               "OTGSC = 0x%08x \n"
-               "USBMODE = 0x%08x \n",
-               readl(langwell->regs + 0x30),
-               readl(langwell->regs + 0x34),
-               readl(langwell->regs + 0x38),
-               readl(langwell->regs + 0x48),
-               readl(langwell->regs + 0x74),
-               readl(langwell->regs + 0xb4),
-               readl(langwell->regs + 0xf4),
-               readl(langwell->regs + 0xf8)
-               );
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
-
-static ssize_t
-show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell = the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size,
-               "\n"
-               "current state = %s\n"
-               "a_bus_resume = \t%d\n"
-               "a_bus_suspend = \t%d\n"
-               "a_conn = \t%d\n"
-               "a_sess_vld = \t%d\n"
-               "a_srp_det = \t%d\n"
-               "a_vbus_vld = \t%d\n"
-               "b_bus_resume = \t%d\n"
-               "b_bus_suspend = \t%d\n"
-               "b_conn = \t%d\n"
-               "b_se0_srp = \t%d\n"
-               "b_sess_end = \t%d\n"
-               "b_sess_vld = \t%d\n"
-               "id = \t%d\n"
-               "a_set_b_hnp_en = \t%d\n"
-               "b_srp_done = \t%d\n"
-               "b_hnp_enable = \t%d\n"
-               "a_wait_vrise_tmout = \t%d\n"
-               "a_wait_bcon_tmout = \t%d\n"
-               "a_aidl_bdis_tmout = \t%d\n"
-               "b_ase0_brst_tmout = \t%d\n"
-               "a_bus_drop = \t%d\n"
-               "a_bus_req = \t%d\n"
-               "a_clr_err = \t%d\n"
-               "a_suspend_req = \t%d\n"
-               "b_bus_req = \t%d\n"
-               "b_bus_suspend_tmout = \t%d\n"
-               "b_bus_suspend_vld = \t%d\n",
-               state_string(langwell->otg.state),
-               langwell->hsm.a_bus_resume,
-               langwell->hsm.a_bus_suspend,
-               langwell->hsm.a_conn,
-               langwell->hsm.a_sess_vld,
-               langwell->hsm.a_srp_det,
-               langwell->hsm.a_vbus_vld,
-               langwell->hsm.b_bus_resume,
-               langwell->hsm.b_bus_suspend,
-               langwell->hsm.b_conn,
-               langwell->hsm.b_se0_srp,
-               langwell->hsm.b_sess_end,
-               langwell->hsm.b_sess_vld,
-               langwell->hsm.id,
-               langwell->hsm.a_set_b_hnp_en,
-               langwell->hsm.b_srp_done,
-               langwell->hsm.b_hnp_enable,
-               langwell->hsm.a_wait_vrise_tmout,
-               langwell->hsm.a_wait_bcon_tmout,
-               langwell->hsm.a_aidl_bdis_tmout,
-               langwell->hsm.b_ase0_brst_tmout,
-               langwell->hsm.a_bus_drop,
-               langwell->hsm.a_bus_req,
-               langwell->hsm.a_clr_err,
-               langwell->hsm.a_suspend_req,
-               langwell->hsm.b_bus_req,
-               langwell->hsm.b_bus_suspend_tmout,
-               langwell->hsm.b_bus_suspend_vld
-               );
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
-
-static ssize_t
-get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_a_bus_req(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.a_bus_req = 0;
-               otg_dbg("a_bus_req = 0\n");
-       } else if (buf[0] == '1') {
-               /* If a_bus_drop is TRUE, a_bus_req can't be set */
-               if (langwell->hsm.a_bus_drop)
-                       return -1;
-               langwell->hsm.a_bus_req = 1;
-               otg_dbg("a_bus_req = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
-
-static ssize_t
-get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_a_bus_drop(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.a_bus_drop = 0;
-               otg_dbg("a_bus_drop = 0\n");
-       } else if (buf[0] == '1') {
-               langwell->hsm.a_bus_drop = 1;
-               langwell->hsm.a_bus_req = 0;
-               otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
-       get_a_bus_drop, set_a_bus_drop);
-
-static ssize_t
-get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct langwell_otg *langwell;
-       char *next;
-       unsigned size;
-       unsigned t;
-
-       langwell =  the_transceiver;
-       next = buf;
-       size = PAGE_SIZE;
-
-       t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req);
-       size -= t;
-       next += t;
-
-       return PAGE_SIZE - size;
-}
-
-static ssize_t
-set_b_bus_req(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-
-       if (langwell->otg.default_a)
-               return -1;
-
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               langwell->hsm.b_bus_req = 0;
-               otg_dbg("b_bus_req = 0\n");
-       } else if (buf[0] == '1') {
-               langwell->hsm.b_bus_req = 1;
-               otg_dbg("b_bus_req = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
-
-static ssize_t
-set_a_clr_err(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct langwell_otg *langwell;
-       langwell = the_transceiver;
-
-       if (!langwell->otg.default_a)
-               return -1;
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '1') {
-               langwell->hsm.a_clr_err = 1;
-               otg_dbg("a_clr_err = 1\n");
-       }
-       if (spin_trylock(&langwell->wq_lock)) {
-               queue_work(langwell->qwork, &langwell->work);
-               spin_unlock(&langwell->wq_lock);
-       }
-       return count;
-}
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
-
-static struct attribute *inputs_attrs[] = {
-       &dev_attr_a_bus_req.attr,
-       &dev_attr_a_bus_drop.attr,
-       &dev_attr_b_bus_req.attr,
-       &dev_attr_a_clr_err.attr,
-       NULL,
-};
-
-static struct attribute_group debug_dev_attr_group = {
-       .name = "inputs",
-       .attrs = inputs_attrs,
-};
-
-int langwell_register_host(struct pci_driver *host_driver)
-{
-       int     ret = 0;
-
-       the_transceiver->host_ops = host_driver;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("host controller driver is registered\n");
-
-       return ret;
-}
-EXPORT_SYMBOL(langwell_register_host);
-
-void langwell_unregister_host(struct pci_driver *host_driver)
-{
-       if (the_transceiver->host_ops)
-               the_transceiver->host_ops->remove(the_transceiver->pdev);
-       the_transceiver->host_ops = NULL;
-       the_transceiver->hsm.a_bus_drop = 1;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("host controller driver is unregistered\n");
-}
-EXPORT_SYMBOL(langwell_unregister_host);
-
-int langwell_register_peripheral(struct pci_driver *client_driver)
-{
-       int     ret = 0;
-
-       if (client_driver)
-               ret = client_driver->probe(the_transceiver->pdev,
-                               client_driver->id_table);
-       if (!ret) {
-               the_transceiver->client_ops = client_driver;
-               queue_work(the_transceiver->qwork, &the_transceiver->work);
-               otg_dbg("client controller driver is registered\n");
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(langwell_register_peripheral);
-
-void langwell_unregister_peripheral(struct pci_driver *client_driver)
-{
-       if (the_transceiver->client_ops)
-               the_transceiver->client_ops->remove(the_transceiver->pdev);
-       the_transceiver->client_ops = NULL;
-       the_transceiver->hsm.b_bus_req = 0;
-       queue_work(the_transceiver->qwork, &the_transceiver->work);
-       otg_dbg("client controller driver is unregistered\n");
-}
-EXPORT_SYMBOL(langwell_unregister_peripheral);
-
-static int langwell_otg_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
-{
-       unsigned long           resource, len;
-       void __iomem            *base = NULL;
-       int                     retval;
-       u32                     val32;
-       struct langwell_otg     *langwell;
-       char                    qname[] = "langwell_otg_queue";
-
-       retval = 0;
-       otg_dbg("\notg controller is detected.\n");
-       if (pci_enable_device(pdev) < 0) {
-               retval = -ENODEV;
-               goto done;
-       }
-
-       langwell = kzalloc(sizeof *langwell, GFP_KERNEL);
-       if (langwell == NULL) {
-               retval = -ENOMEM;
-               goto done;
-       }
-       the_transceiver = langwell;
-
-       /* control register: BAR 0 */
-       resource = pci_resource_start(pdev, 0);
-       len = pci_resource_len(pdev, 0);
-       if (!request_mem_region(resource, len, driver_name)) {
-               retval = -EBUSY;
-               goto err;
-       }
-       langwell->region = 1;
-
-       base = ioremap_nocache(resource, len);
-       if (base == NULL) {
-               retval = -EFAULT;
-               goto err;
-       }
-       langwell->regs = base;
-
-       if (!pdev->irq) {
-               otg_dbg("No IRQ.\n");
-               retval = -ENODEV;
-               goto err;
-       }
-
-       langwell->qwork = create_workqueue(qname);
-       if (!langwell->qwork) {
-               otg_dbg("cannot create workqueue %s\n", qname);
-               retval = -ENOMEM;
-               goto err;
-       }
-       INIT_WORK(&langwell->work, langwell_otg_work);
-
-       /* OTG common part */
-       langwell->pdev = pdev;
-       langwell->otg.dev = &pdev->dev;
-       langwell->otg.label = driver_name;
-       langwell->otg.set_host = langwell_otg_set_host;
-       langwell->otg.set_peripheral = langwell_otg_set_peripheral;
-       langwell->otg.set_power = langwell_otg_set_power;
-       langwell->otg.start_srp = langwell_otg_start_srp;
-       langwell->otg.state = OTG_STATE_UNDEFINED;
-       if (otg_set_transceiver(&langwell->otg)) {
-               otg_dbg("can't set transceiver\n");
-               retval = -EBUSY;
-               goto err;
-       }
-
-       reset_otg();
-       init_hsm();
-
-       spin_lock_init(&langwell->lock);
-       spin_lock_init(&langwell->wq_lock);
-       INIT_LIST_HEAD(&active_timers);
-       langwell_otg_init_timers(&langwell->hsm);
-
-       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
-                               driver_name, langwell) != 0) {
-               otg_dbg("request interrupt %d failed\n", pdev->irq);
-               retval = -EBUSY;
-               goto err;
-       }
-
-       /* enable OTGSC int */
-       val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
-               OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
-       writel(val32, langwell->regs + CI_OTGSC);
-
-       retval = device_create_file(&pdev->dev, &dev_attr_registers);
-       if (retval < 0) {
-               otg_dbg("Can't register sysfs attribute: %d\n", retval);
-               goto err;
-       }
-
-       retval = device_create_file(&pdev->dev, &dev_attr_hsm);
-       if (retval < 0) {
-               otg_dbg("Can't hsm sysfs attribute: %d\n", retval);
-               goto err;
-       }
-
-       retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
-       if (retval < 0) {
-               otg_dbg("Can't register sysfs attr group: %d\n", retval);
-               goto err;
-       }
-
-       if (langwell->otg.state == OTG_STATE_A_IDLE)
-               queue_work(langwell->qwork, &langwell->work);
-
-       return 0;
-
-err:
-       if (the_transceiver)
-               langwell_otg_remove(pdev);
-done:
-       return retval;
-}
-
-static void langwell_otg_remove(struct pci_dev *pdev)
-{
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       if (langwell->qwork) {
-               flush_workqueue(langwell->qwork);
-               destroy_workqueue(langwell->qwork);
-       }
-       langwell_otg_free_timers();
-
-       /* disable OTGSC interrupt as OTGSC doesn't change in reset */
-       writel(0, langwell->regs + CI_OTGSC);
-
-       if (pdev->irq)
-               free_irq(pdev->irq, langwell);
-       if (langwell->regs)
-               iounmap(langwell->regs);
-       if (langwell->region)
-               release_mem_region(pci_resource_start(pdev, 0),
-                               pci_resource_len(pdev, 0));
-
-       otg_set_transceiver(NULL);
-       pci_disable_device(pdev);
-       sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
-       device_remove_file(&pdev->dev, &dev_attr_hsm);
-       device_remove_file(&pdev->dev, &dev_attr_registers);
-       kfree(langwell);
-       langwell = NULL;
-}
-
-static void transceiver_suspend(struct pci_dev *pdev)
-{
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       langwell_otg_phy_low_power(1);
-}
-
-static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
-{
-       int     ret = 0;
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       /* Disbale OTG interrupts */
-       langwell_otg_intr(0);
-
-       if (pdev->irq)
-               free_irq(pdev->irq, langwell);
-
-       /* Prevent more otg_work */
-       flush_workqueue(langwell->qwork);
-       spin_lock(&langwell->wq_lock);
-
-       /* start actions */
-       switch (langwell->otg.state) {
-       case OTG_STATE_A_IDLE:
-       case OTG_STATE_B_IDLE:
-       case OTG_STATE_A_WAIT_VFALL:
-       case OTG_STATE_A_VBUS_ERR:
-               transceiver_suspend(pdev);
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               langwell_otg_del_timer(a_wait_vrise_tmr);
-               langwell->hsm.a_srp_det = 0;
-               langwell_otg_drv_vbus(0);
-               langwell->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               langwell_otg_del_timer(a_wait_bcon_tmr);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->suspend(pdev, message);
-               langwell_otg_drv_vbus(0);
-               break;
-       case OTG_STATE_A_HOST:
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->suspend(pdev, message);
-               langwell_otg_drv_vbus(0);
-               langwell_otg_phy_low_power(1);
-               break;
-       case OTG_STATE_A_SUSPEND:
-               langwell_otg_del_timer(a_aidl_bdis_tmr);
-               langwell_otg_HABA(0);
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell_otg_drv_vbus(0);
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->suspend(pdev, message);
-               else
-                       otg_dbg("client driver has been removed.\n");
-               langwell_otg_drv_vbus(0);
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
-               break;
-       case OTG_STATE_B_HOST:
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell->hsm.b_bus_req = 0;
-               transceiver_suspend(pdev);
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->suspend(pdev, message);
-               else
-                       otg_dbg("client driver has been removed.\n");
-               break;
-       case OTG_STATE_B_WAIT_ACON:
-               langwell_otg_del_timer(b_ase0_brst_tmr);
-               langwell_otg_HAAR(0);
-               if (langwell->host_ops)
-                       langwell->host_ops->remove(pdev);
-               else
-                       otg_dbg("host driver has been removed.\n");
-               langwell->hsm.b_bus_req = 0;
-               langwell->otg.state = OTG_STATE_B_IDLE;
-               transceiver_suspend(pdev);
-               break;
-       default:
-               otg_dbg("error state before suspend\n ");
-               break;
-       }
-       spin_unlock(&langwell->wq_lock);
-
-       return ret;
-}
-
-static void transceiver_resume(struct pci_dev *pdev)
-{
-       pci_restore_state(pdev);
-       pci_set_power_state(pdev, PCI_D0);
-       langwell_otg_phy_low_power(0);
-}
-
-static int langwell_otg_resume(struct pci_dev *pdev)
-{
-       int     ret = 0;
-       struct langwell_otg *langwell;
-
-       langwell = the_transceiver;
-
-       spin_lock(&langwell->wq_lock);
-
-       switch (langwell->otg.state) {
-       case OTG_STATE_A_IDLE:
-       case OTG_STATE_B_IDLE:
-       case OTG_STATE_A_WAIT_VFALL:
-       case OTG_STATE_A_VBUS_ERR:
-               transceiver_resume(pdev);
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               langwell_otg_add_timer(a_wait_bcon_tmr);
-               langwell_otg_drv_vbus(1);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->resume(pdev);
-               break;
-       case OTG_STATE_A_HOST:
-               langwell_otg_drv_vbus(1);
-               langwell_otg_phy_low_power(0);
-               if (langwell->host_ops)
-                       ret = langwell->host_ops->resume(pdev);
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (langwell->client_ops)
-                       ret = langwell->client_ops->resume(pdev);
-               else
-                       otg_dbg("client driver not loaded.\n");
-               break;
-       default:
-               otg_dbg("error state before suspend\n ");
-               break;
-       }
-
-       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
-                               driver_name, the_transceiver) != 0) {
-               otg_dbg("request interrupt %d failed\n", pdev->irq);
-               ret = -EBUSY;
-       }
-
-       /* enable OTG interrupts */
-       langwell_otg_intr(1);
-
-       spin_unlock(&langwell->wq_lock);
-
-       queue_work(langwell->qwork, &langwell->work);
-
-
-       return ret;
-}
-
-static int __init langwell_otg_init(void)
-{
-       return pci_register_driver(&otg_pci_driver);
-}
-module_init(langwell_otg_init);
-
-static void __exit langwell_otg_cleanup(void)
-{
-       pci_unregister_driver(&otg_pci_driver);
-}
-module_exit(langwell_otg_cleanup);
index 9ed5ea568679c3715eae4a03700d1ff8bd05e409..af456b48985f06f3ebe09ae43363f47f7d0bfec7 100644 (file)
@@ -53,6 +53,7 @@ EXPORT_SYMBOL(usb_nop_xceiv_register);
 void usb_nop_xceiv_unregister(void)
 {
        platform_device_unregister(pd);
+       pd = NULL;
 }
 EXPORT_SYMBOL(usb_nop_xceiv_unregister);
 
index 247b61bfb7f45f4d179abd6ef36f9611eea046da..0e4f2e41ace5b064193a46d3409d98df9099c117 100644 (file)
@@ -169,9 +169,11 @@ static int usb_console_setup(struct console *co, char *options)
                        kfree(tty);
                }
        }
-       /* So we know not to kill the hardware on a hangup on this
-          port. We have also bumped the use count by one so it won't go
-          idle */
+       /* Now that any required fake tty operations are completed restore
+        * the tty port count */
+       --port->port.count;
+       /* The console is special in terms of closing the device so
+        * indicate this port is now acting as a system console. */
        port->console = 1;
        retval = 0;
 
@@ -204,7 +206,7 @@ static void usb_console_write(struct console *co,
 
        dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
 
-       if (!port->port.count) {
+       if (!port->console) {
                dbg("%s - port not opened", __func__);
                return;
        }
@@ -300,8 +302,7 @@ void usb_serial_console_exit(void)
 {
        if (usbcons_info.port) {
                unregister_console(&usbcons);
-               if (usbcons_info.port->port.count)
-                       usbcons_info.port->port.count--;
+               usbcons_info.port->console = 0;
                usbcons_info.port = NULL;
        }
 }
index 2b9eeda62bfe7beb12a4b3abb8aec6b3954e9f9c..985cbcf48bda83317d235395fbbca689f5649ee1 100644 (file)
@@ -67,6 +67,8 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
        { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
+       { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
+       { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
        { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
@@ -78,6 +80,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
        { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
        { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
+       { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
        { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
        { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
        { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
@@ -94,7 +97,9 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
        { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
+       { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
        { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+       { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
index 9734085fd2fee19f99051320db97ae22d867dc1e..59adfe123110b5e3c631f2ffa111d5b3c56680a7 100644 (file)
@@ -1228,8 +1228,8 @@ static void cypress_read_int_callback(struct urb *urb)
                /* precursor to disconnect so just go away */
                return;
        case -EPIPE:
-               usb_clear_halt(port->serial->dev, 0x81);
-               break;
+               /* Can't call usb_clear_halt while in_interrupt */
+               /* FALLS THROUGH */
        default:
                /* something ugly is going on... */
                dev_err(&urb->dev->dev,
index 3dc3768ca71ca0afb4a2a8f19541b3b345787b72..b574878c78b27b633a056d96cf3eb36a25d098b6 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -107,6 +108,7 @@ struct ftdi_sio_quirk {
 
 static int   ftdi_jtag_probe(struct usb_serial *serial);
 static int   ftdi_mtxorb_hack_setup(struct usb_serial *serial);
+static int   ftdi_NDI_device_setup(struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
 
@@ -118,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = {
        .probe  = ftdi_mtxorb_hack_setup,
 };
 
+static struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
+       .probe  = ftdi_NDI_device_setup,
+};
+
 static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
        .port_probe = ftdi_USB_UIRT_setup,
 };
@@ -191,6 +197,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
@@ -579,6 +586,9 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
        { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
        { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
        { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -644,6 +654,16 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
        { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
@@ -660,6 +680,8 @@ static struct usb_device_id id_table_combined [] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
        { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
        { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
@@ -667,7 +689,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
        { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
        { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },
        { USB_DEVICE(ATMEL_VID, STK541_PID) },
        { USB_DEVICE(DE_VID, STB_PID) },
        { USB_DEVICE(DE_VID, WHT_PID) },
@@ -677,6 +698,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
+       { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1023,6 +1045,16 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
        case FT2232C: /* FT2232C chip */
        case FT232RL:
                if (baud <= 3000000) {
+                       __u16 product_id = le16_to_cpu(
+                               port->serial->dev->descriptor.idProduct);
+                       if (((FTDI_NDI_HUC_PID == product_id) ||
+                            (FTDI_NDI_SPECTRA_SCU_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_2_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_3_PID == product_id) ||
+                            (FTDI_NDI_AURORA_SCU_PID == product_id)) &&
+                           (baud == 19200)) {
+                               baud = 1200000;
+                       }
                        div_value = ftdi_232bm_baud_to_divisor(baud);
                } else {
                        dbg("%s - Baud rate too high!", __func__);
@@ -1553,6 +1585,39 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
        priv->force_rtscts = 1;
 } /* ftdi_HE_TIRA1_setup */
 
+/*
+ * Module parameter to control latency timer for NDI FTDI-based USB devices.
+ * If this value is not set in modprobe.conf.local its value will be set to 1ms.
+ */
+static int ndi_latency_timer = 1;
+
+/* Setup for the NDI FTDI-based USB devices, which requires hardwired
+ * baudrate (19200 gets mapped to 1200000).
+ *
+ * Called from usbserial:serial_probe.
+ */
+static int ftdi_NDI_device_setup(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       int latency = ndi_latency_timer;
+       int rv = 0;
+       char buf[1];
+
+       if (latency == 0)
+               latency = 1;
+       if (latency > 99)
+               latency = 99;
+
+       dbg("%s setting NDI device latency to %d", __func__, latency);
+       dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
+
+       rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+                               latency, 0, buf, 0, WDR_TIMEOUT);
+       return 0;
+}
+
 /*
  * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
  * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
@@ -2121,7 +2186,7 @@ static void ftdi_process_read(struct work_struct *work)
                                /* Note that the error flag is duplicated for
                                   every character received since we don't know
                                   which character it applied to */
-                               if (!usb_serial_handle_sysrq_char(port,
+                               if (!usb_serial_handle_sysrq_char(tty, port,
                                                data[packet_offset + i]))
                                        tty_insert_flip_char(tty,
                                                data[packet_offset + i],
@@ -2622,3 +2687,5 @@ MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified product ID");
 
+module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
index f1d440a728a376770617ad7776a52eba590cc282..24dbd99e87d722a95beac152af27a475c46cac2b 100644 (file)
  *
  * Armin Laeuger originally sent the PID for the UM 100 module.
  */
+#define FTDI_R2000KU_TRUE_RNG  0xFB80  /* R2000KU TRUE RNG */
 #define FTDI_ELV_UR100_PID     0xFB58  /* USB-RS232-Umsetzer (UR 100) */
 #define FTDI_ELV_UM100_PID     0xFB5A  /* USB-Modul UM 100 */
 #define FTDI_ELV_UO100_PID     0xFB5B  /* USB-Modul UO 100 */
 #define FTDI_CCSICDU20_0_PID    0xF9D0
 #define FTDI_CCSICDU40_1_PID    0xF9D1
 #define FTDI_CCSMACHX_2_PID     0xF9D2
+#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
+#define FTDI_CCSICDU64_4_PID    0xF9D4
+#define FTDI_CCSPRIME8_5_PID    0xF9D5
 
 /* Inside Accesso contactless reader (http://www.insidefr.com) */
 #define INSIDE_ACCESSO         0xFAD0
 /* Pyramid Computer GmbH */
 #define FTDI_PYRAMID_PID       0xE6C8  /* Pyramid Appliance Display */
 
+/*
+ * NDI (www.ndigital.com) product ids
+ */
+#define FTDI_NDI_HUC_PID               0xDA70  /* NDI Host USB Converter */
+#define FTDI_NDI_SPECTRA_SCU_PID       0xDA71  /* NDI Spectra SCU */
+#define FTDI_NDI_FUTURE_2_PID          0xDA72  /* NDI future device #2 */
+#define FTDI_NDI_FUTURE_3_PID          0xDA73  /* NDI future device #3 */
+#define FTDI_NDI_AURORA_SCU_PID                0xDA74  /* NDI Aurora SCU */
+
 /*
  * Posiflex inc retail equipment (http://www.posiflex.com.tw)
  */
 #define TML_VID                        0x1B91  /* Vendor ID */
 #define TML_USB_SERIAL_PID     0x0064  /* USB - Serial Converter */
 
-/* NDI Polaris System */
-#define FTDI_NDI_HUC_PID        0xDA70
-
 /* Propox devices */
 #define FTDI_PROPOX_JTAGCABLEII_PID    0xD738
 
 #define MARVELL_VID            0x9e88
 #define MARVELL_SHEEVAPLUG_PID 0x9e8f
 
+#define FTDI_TURTELIZER_PID    0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
+
+/*
+ * GN Otometrics (http://www.otometrics.com)
+ * Submitted by Ville Sundberg.
+ */
+#define GN_OTOMETRICS_VID      0x0c33  /* Vendor ID */
+#define AURICAL_USB_PID                0x0010  /* Aurical USB Audiometer */
+
 /*
  *   BmRequestType:  1100 0000b
  *   bRequest:       FTDI_E2_READ
index 932d6241b787d2c399bae70f70bec85e4c979d71..ce57f6a32bdfb4cc7a5e30f78c1e8eca21a9364a 100644 (file)
@@ -424,10 +424,17 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
        if (!tty)
                goto done;
 
-       /* Push data to tty */
-       for (i = 0; i < urb->actual_length; i++, ch++) {
-               if (!usb_serial_handle_sysrq_char(port, *ch))
-                       tty_insert_flip_char(tty, *ch, TTY_NORMAL);
+       /* The per character mucking around with sysrq path it too slow for
+          stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases
+          where the USB serial is not a console anyway */
+       if (!port->console || !port->sysrq)
+               tty_insert_flip_string(tty, ch, urb->actual_length);
+       else {
+               /* Push data to tty */
+               for (i = 0; i < urb->actual_length; i++, ch++) {
+                       if (!usb_serial_handle_sysrq_char(tty, port, *ch))
+                               tty_insert_flip_char(tty, *ch, TTY_NORMAL);
+               }
        }
        tty_flip_buffer_push(tty);
        tty_kref_put(tty);
@@ -527,11 +534,12 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
        }
 }
 
-int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
+int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+                       struct usb_serial_port *port, unsigned int ch)
 {
        if (port->sysrq && port->console) {
                if (ch && time_before(jiffies, port->sysrq)) {
-                       handle_sysrq(ch, tty_port_tty_get(&port->port));
+                       handle_sysrq(ch, tty);
                        port->sysrq = 0;
                        return 1;
                }
index bfc5ce000ef92e8d664407dfd62dbf0ba4592832..ccd4dd340d2cff34ed7cedcd9c108a8be5e856f6 100644 (file)
@@ -521,7 +521,7 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty)
        mos7720_port = usb_get_serial_port_data(port);
        if (mos7720_port == NULL) {
                dbg("%s:leaving ...........", __func__);
-               return -ENODEV;
+               return 0;
        }
 
        for (i = 0; i < NUM_URBS; ++i) {
index c40f95c1951cf0cf17e8fedc4e8e9f4782324c67..270009afdf77043f2e60034b8d29182dad053edf 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #define BANDB_DEVICE_ID_USOPTL4_4       0xAC44
 #define BANDB_DEVICE_ID_USOPTL4_2       0xAC42
 
-/* This driver also supports the ATEN UC2324 device since it is mos7840 based
- *  - if I knew the device id it would also support the ATEN UC2322 */
+/* This driver also supports
+ * ATEN UC2324 device using Moschip MCS7840
+ * ATEN UC2322 device using Moschip MCS7820
+ */
 #define USB_VENDOR_ID_ATENINTL         0x0557
 #define ATENINTL_DEVICE_ID_UC2324      0x2011
+#define ATENINTL_DEVICE_ID_UC2322      0x7820
 
 /* Interrupt Routine Defines    */
 
@@ -176,6 +180,7 @@ static struct usb_device_id moschip_port_id_table[] = {
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
        {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
+       {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
        {}                      /* terminating entry */
 };
 
@@ -185,6 +190,7 @@ static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
        {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
+       {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
        {}                      /* terminating entry */
 };
 
index 575816e6ba371fb4ef5fbeeba3668e559b86bfe2..c784ddbe7b614cf13b4e57ab1fbd6ad2efdf3121 100644 (file)
@@ -66,8 +66,10 @@ static int  option_tiocmget(struct tty_struct *tty, struct file *file);
 static int  option_tiocmset(struct tty_struct *tty, struct file *file,
                                unsigned int set, unsigned int clear);
 static int  option_send_setup(struct usb_serial_port *port);
+#ifdef CONFIG_PM
 static int  option_suspend(struct usb_serial *serial, pm_message_t message);
 static int  option_resume(struct usb_serial *serial);
+#endif
 
 /* Vendor and product IDs */
 #define OPTION_VENDOR_ID                       0x0AF0
@@ -205,7 +207,9 @@ static int  option_resume(struct usb_serial *serial);
 #define NOVATELWIRELESS_PRODUCT_MC727          0x4100
 #define NOVATELWIRELESS_PRODUCT_MC950D         0x4400
 #define NOVATELWIRELESS_PRODUCT_U727           0x5010
+#define NOVATELWIRELESS_PRODUCT_MC727_NEW      0x5100
 #define NOVATELWIRELESS_PRODUCT_MC760          0x6000
+#define NOVATELWIRELESS_PRODUCT_OVMC760                0x6002
 
 /* FUTURE NOVATEL PRODUCTS */
 #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001
@@ -258,11 +262,6 @@ static int  option_resume(struct usb_serial *serial);
 #define AXESSTEL_VENDOR_ID                     0x1726
 #define AXESSTEL_PRODUCT_MV110H                        0x1000
 
-#define ONDA_VENDOR_ID                         0x19d2
-#define ONDA_PRODUCT_MSA501HS                  0x0001
-#define ONDA_PRODUCT_ET502HS                   0x0002
-#define ONDA_PRODUCT_MT503HS                   0x2000
-
 #define BANDRICH_VENDOR_ID                     0x1A8D
 #define BANDRICH_PRODUCT_C100_1                        0x1002
 #define BANDRICH_PRODUCT_C100_2                        0x1003
@@ -300,6 +299,7 @@ static int  option_resume(struct usb_serial *serial);
 #define ZTE_PRODUCT_MF628                      0x0015
 #define ZTE_PRODUCT_MF626                      0x0031
 #define ZTE_PRODUCT_CDMA_TECH                  0xfffe
+#define ZTE_PRODUCT_AC8710                     0xfff1
 
 #define BENQ_VENDOR_ID                         0x04a5
 #define BENQ_PRODUCT_H10                       0x4068
@@ -307,11 +307,25 @@ static int  option_resume(struct usb_serial *serial);
 #define DLINK_VENDOR_ID                                0x1186
 #define DLINK_PRODUCT_DWM_652                  0x3e04
 
+#define QISDA_VENDOR_ID                                0x1da5
+#define QISDA_PRODUCT_H21_4512                 0x4512
+#define QISDA_PRODUCT_H21_4523                 0x4523
+#define QISDA_PRODUCT_H20_4515                 0x4515
+#define QISDA_PRODUCT_H20_4519                 0x4519
+
 
 /* TOSHIBA PRODUCTS */
 #define TOSHIBA_VENDOR_ID                      0x0930
 #define TOSHIBA_PRODUCT_HSDPA_MINICARD         0x1302
 
+#define ALINK_VENDOR_ID                                0x1e0e
+#define ALINK_PRODUCT_3GU                      0x9200
+
+/* ALCATEL PRODUCTS */
+#define ALCATEL_VENDOR_ID                      0x1bbb
+#define ALCATEL_PRODUCT_X060S                  0x0000
+
+
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -428,8 +442,10 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727_NEW) }, /* Novatel MC727/U727/USB727 refresh */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */
@@ -463,42 +479,6 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
        { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
-       { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
-       { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0003) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0004) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0005) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0006) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0007) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0008) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0009) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000a) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000b) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000c) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000d) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000e) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x000f) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0010) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0011) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0012) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0013) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0014) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0015) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0016) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0017) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0018) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0019) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0020) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0021) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0022) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0023) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0024) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0025) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0026) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0027) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0028) },
-       { USB_DEVICE(ONDA_VENDOR_ID, 0x0029) },
-       { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) },
        { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
@@ -523,14 +503,85 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
        { USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
-       { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622) },
-       { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
-       { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
-       { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000b, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000c, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000d, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000e, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0082, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
        { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
        { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
-       { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
        { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
+       { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
+       { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -539,8 +590,10 @@ static struct usb_driver option_driver = {
        .name       = "option",
        .probe      = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
+#ifdef CONFIG_PM
        .suspend    = usb_serial_suspend,
        .resume     = usb_serial_resume,
+#endif
        .id_table   = option_ids,
        .no_dynamic_id =        1,
 };
@@ -572,8 +625,10 @@ static struct usb_serial_driver option_1port_device = {
        .disconnect        = option_disconnect,
        .release           = option_release,
        .read_int_callback = option_instat_callback,
+#ifdef CONFIG_PM
        .suspend           = option_suspend,
        .resume            = option_resume,
+#endif
 };
 
 static int debug;
@@ -732,7 +787,6 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
                memcpy(this_urb->transfer_buffer, buf, todo);
                this_urb->transfer_buffer_length = todo;
 
-               this_urb->dev = port->serial->dev;
                err = usb_submit_urb(this_urb, GFP_ATOMIC);
                if (err) {
                        dbg("usb_submit_urb %p (write bulk) failed "
@@ -816,7 +870,6 @@ static void option_instat_callback(struct urb *urb)
        int status = urb->status;
        struct usb_serial_port *port =  urb->context;
        struct option_port_private *portdata = usb_get_serial_port_data(port);
-       struct usb_serial *serial = port->serial;
 
        dbg("%s", __func__);
        dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
@@ -860,7 +913,6 @@ static void option_instat_callback(struct urb *urb)
 
        /* Resubmit urb so we continue receiving IRQ data */
        if (status != -ESHUTDOWN && status != -ENOENT) {
-               urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err)
                        dbg("%s: resubmit intr urb failed. (%d)",
@@ -913,7 +965,6 @@ static int option_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
 {
        struct option_port_private *portdata;
-       struct usb_serial *serial = port->serial;
        int i, err;
        struct urb *urb;
 
@@ -921,23 +972,11 @@ static int option_open(struct tty_struct *tty,
 
        dbg("%s", __func__);
 
-       /* Reset low level data toggle and start reading from endpoints */
+       /* Start reading from the IN endpoint */
        for (i = 0; i < N_IN_URB; i++) {
                urb = portdata->in_urbs[i];
                if (!urb)
                        continue;
-               if (urb->dev != serial->dev) {
-                       dbg("%s: dev %p != %p", __func__,
-                               urb->dev, serial->dev);
-                       continue;
-               }
-
-               /*
-                * make sure endpoint data toggle is synchronized with the
-                * device
-                */
-               usb_clear_halt(urb->dev, urb->pipe);
-
                err = usb_submit_urb(urb, GFP_KERNEL);
                if (err) {
                        dbg("%s: submit urb %d failed (%d) %d",
@@ -946,16 +985,6 @@ static int option_open(struct tty_struct *tty,
                }
        }
 
-       /* Reset low level data toggle on out endpoints */
-       for (i = 0; i < N_OUT_URB; i++) {
-               urb = portdata->out_urbs[i];
-               if (!urb)
-                       continue;
-               urb->dev = serial->dev;
-               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                               usb_pipeout(urb->pipe), 0); */
-       }
-
        option_send_setup(port);
 
        return 0;
@@ -1195,6 +1224,7 @@ static void option_release(struct usb_serial *serial)
        }
 }
 
+#ifdef CONFIG_PM
 static int option_suspend(struct usb_serial *serial, pm_message_t message)
 {
        dbg("%s entered", __func__);
@@ -1218,7 +1248,6 @@ static int option_resume(struct usb_serial *serial)
                        dbg("%s: No interrupt URB for port %d\n", __func__, i);
                        continue;
                }
-               port->interrupt_in_urb->dev = serial->dev;
                err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
                dbg("Submitted interrupt URB for port %d (result %d)", i, err);
                if (err < 0) {
@@ -1254,6 +1283,7 @@ static int option_resume(struct usb_serial *serial)
        }
        return 0;
 }
+#endif
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
index ec6c132a25b56f0a63ffa3b0b3a702594d1097b3..7d15bfa7c2dbfeb1c19768a2499ee2178d14efe0 100644 (file)
@@ -94,6 +94,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
        { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
+       { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -971,18 +972,46 @@ exit:
                        __func__, retval);
 }
 
+static void pl2303_push_data(struct tty_struct *tty,
+               struct usb_serial_port *port, struct urb *urb,
+               u8 line_status)
+{
+       unsigned char *data = urb->transfer_buffer;
+       /* get tty_flag from status */
+       char tty_flag = TTY_NORMAL;
+       /* break takes precedence over parity, */
+       /* which takes precedence over framing errors */
+       if (line_status & UART_BREAK_ERROR)
+               tty_flag = TTY_BREAK;
+       else if (line_status & UART_PARITY_ERROR)
+               tty_flag = TTY_PARITY;
+       else if (line_status & UART_FRAME_ERROR)
+               tty_flag = TTY_FRAME;
+       dbg("%s - tty_flag = %d", __func__, tty_flag);
+
+       tty_buffer_request_room(tty, urb->actual_length + 1);
+       /* overrun is special, not associated with a char */
+       if (line_status & UART_OVERRUN_ERROR)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       if (port->console && port->sysrq) {
+               int i;
+               for (i = 0; i < urb->actual_length; ++i)
+                       if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
+                               tty_insert_flip_char(tty, data[i], tty_flag);
+       } else
+               tty_insert_flip_string(tty, data, urb->actual_length);
+       tty_flip_buffer_push(tty);
+}
+
 static void pl2303_read_bulk_callback(struct urb *urb)
 {
        struct usb_serial_port *port =  urb->context;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        struct tty_struct *tty;
-       unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
-       int i;
        int result;
        int status = urb->status;
        u8 line_status;
-       char tty_flag;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -1010,10 +1039,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
        }
 
        usb_serial_debug_data(debug, &port->dev, __func__,
-                             urb->actual_length, data);
-
-       /* get tty_flag from status */
-       tty_flag = TTY_NORMAL;
+                             urb->actual_length, urb->transfer_buffer);
 
        spin_lock_irqsave(&priv->lock, flags);
        line_status = priv->line_status;
@@ -1021,26 +1047,9 @@ static void pl2303_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
        wake_up_interruptible(&priv->delta_msr_wait);
 
-       /* break takes precedence over parity, */
-       /* which takes precedence over framing errors */
-       if (line_status & UART_BREAK_ERROR)
-               tty_flag = TTY_BREAK;
-       else if (line_status & UART_PARITY_ERROR)
-               tty_flag = TTY_PARITY;
-       else if (line_status & UART_FRAME_ERROR)
-               tty_flag = TTY_FRAME;
-       dbg("%s - tty_flag = %d", __func__, tty_flag);
-
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length + 1);
-               /* overrun is special, not associated with a char */
-               if (line_status & UART_OVERRUN_ERROR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               for (i = 0; i < urb->actual_length; ++i)
-                       if (!usb_serial_handle_sysrq_char(port, data[i]))
-                               tty_insert_flip_char(tty, data[i], tty_flag);
-               tty_flip_buffer_push(tty);
+               pl2303_push_data(tty, port, urb, line_status);
        }
        tty_kref_put(tty);
        /* Schedule the next read _if_ we are still open */
index 1d7a22e3a9fd1daa5df3c239185670763e7a5563..12aac7d2462dab327105a2fcf1f5344672efe121 100644 (file)
 /* Hewlett-Packard LD220-HP POS Pole Display */
 #define HP_VENDOR_ID           0x03f0
 #define HP_LD220_PRODUCT_ID    0x3524
+
+/* Cressi Edy (diving computer) PC interface */
+#define CRESSI_VENDOR_ID       0x04b8
+#define CRESSI_EDY_PRODUCT_ID  0x0521
index 032f7aeb40a42b17b71b1f4c2ae7b3d1ff221640..f48d05e0acc135e89a5e4a7518f3d1364b07e35d 100644 (file)
@@ -181,35 +181,50 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = {
 };
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
+       { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
+       { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
+
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
        { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
+       { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */
+       { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
+       { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
        { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
-        /* Sierra Wireless C597 */
+       /* Sierra Wireless C597 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) },
-        /* Sierra Wireless Device */
+       /* Sierra Wireless T598 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
-       { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */
-       { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */
-       { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */
+       { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */
+       { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */
+       { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */
+       { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */
 
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
-       { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Lenovo) */
+       { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */
-       { USB_DEVICE(0x03f0, 0x1e1d) }, /* HP hs2300 a.k.a MC8775 */
+       { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
        { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
+       { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */
        { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */
        { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
+       { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */
+       { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */
+       { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */
+       { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */
        { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
        { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
        /* Sierra Wireless MC8790, MC8791, MC8792 Composite */
@@ -227,16 +242,13 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
        /* Sierra Wireless C885 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless C22/C33 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
-       /* Sierra Wireless Device */
+       /* Sierra Wireless HSPA Non-Composite Device */
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
-
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-       { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
-
+       { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */
        { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
@@ -814,7 +826,7 @@ static int sierra_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void sierra_disconnect(struct usb_serial *serial)
+static void sierra_release(struct usb_serial *serial)
 {
        int i;
        struct usb_serial_port *port;
@@ -830,7 +842,6 @@ static void sierra_disconnect(struct usb_serial *serial)
                if (!portdata)
                        continue;
                kfree(portdata);
-               usb_set_serial_port_data(port, NULL);
        }
 }
 
@@ -853,7 +864,7 @@ static struct usb_serial_driver sierra_device = {
        .tiocmget          = sierra_tiocmget,
        .tiocmset          = sierra_tiocmset,
        .attach            = sierra_startup,
-       .disconnect        = sierra_disconnect,
+       .release           = sierra_release,
        .read_int_callback = sierra_instat_callback,
 };
 
index 991d8232e3765c39de562ec8e09181d0e8d4c547..3bc609fe2242a574643fe84353cf9de665fc25e3 100644 (file)
@@ -191,7 +191,6 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
-       { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
 };
 
 static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = {
@@ -728,7 +727,7 @@ static int ti_write_room(struct tty_struct *tty)
        dbg("%s - port %d", __func__, port->number);
 
        if (tport == NULL)
-               return -ENODEV;
+               return 0;
 
        spin_lock_irqsave(&tport->tp_lock, flags);
        room = ti_buf_space_avail(tport->tp_write_buf);
@@ -749,7 +748,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
        dbg("%s - port %d", __func__, port->number);
 
        if (tport == NULL)
-               return -ENODEV;
+               return 0;
 
        spin_lock_irqsave(&tport->tp_lock, flags);
        chars = ti_buf_data_avail(tport->tp_write_buf);
@@ -1658,7 +1657,7 @@ static int ti_do_download(struct usb_device *dev, int pipe,
        u8 cs = 0;
        int done;
        struct ti_firmware_header *header;
-       int status;
+       int status = 0;
        int len;
 
        for (pos = sizeof(struct ti_firmware_header); pos < size; pos++)
index a84216464ca01fa60a687974f0324b86bffdc137..99188c92068bb4492416ff99b7655086721c9034 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -31,6 +32,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/uaccess.h>
+#include <linux/serial.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include "pl2303.h"
@@ -183,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
        struct usb_serial_port *port;
        unsigned int portNumber;
        int retval = 0;
+       int first = 0;
 
        dbg("%s", __func__);
 
@@ -220,8 +223,9 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
        tty->driver_data = port;
        tty_port_tty_set(&port->port, tty);
 
-       if (port->port.count == 1) {
-
+       /* If the console is attached, the device is already open */
+       if (port->port.count == 1 && !port->console) {
+               first = 1;
                /* lock this module before we call it
                 * this may fail, which means we must bail out,
                 * safe because we are called with BKL held */
@@ -244,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
                if (retval)
                        goto bailout_interface_put;
                mutex_unlock(&serial->disc_mutex);
+               set_bit(ASYNCB_INITIALIZED, &port->port.flags);
        }
        mutex_unlock(&port->mutex);
        /* Now do the correct tty layer semantics */
        retval = tty_port_block_til_ready(&port->port, tty, filp);
-       if (retval == 0)
+       if (retval == 0) {
+               if (!first)
+                       usb_serial_put(serial);
                return 0;
-
+       }
+       mutex_lock(&port->mutex);
+       if (first == 0)
+               goto bailout_mutex_unlock;
+       /* Undo the initial port actions */
+       mutex_lock(&serial->disc_mutex);
 bailout_interface_put:
        usb_autopm_put_interface(serial->interface);
 bailout_module_put:
@@ -338,6 +350,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 
        dbg("%s - port %d", __func__, port->number);
 
+       /* FIXME:
+          This leaves a very narrow race. Really we should do the
+          serial_do_free() on tty->shutdown(), but tty->shutdown can
+          be called from IRQ context and serial_do_free can sleep.
+
+          The right fix is probably to make the tty free (which is rare)
+          and thus tty->shutdown() occur via a work queue and simplify all
+          the drivers that use it.
+       */
+       if (tty_hung_up_p(filp)) {
+               /* serial_hangup already called serial_down at this point.
+                  Another user may have already reopened the port but
+                  serial_do_free is refcounted */
+               serial_do_free(port);
+               return;
+       }
 
        if (tty_port_close_start(&port->port, tty, filp) == 0)
                return;
@@ -353,7 +381,8 @@ static void serial_hangup(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        serial_do_down(port);
        tty_port_hangup(&port->port);
-       serial_do_free(port);
+       /* We must not free port yet - the USB serial layer depends on it's
+          continued existence */
 }
 
 static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@@ -392,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s = port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        /* if the device was unplugged then any remaining characters
           fell out of the connector ;) */
        if (port->serial->disconnected)
index d41cc0a970f79a147660da239bdc014612396354..773a5cd38c5aa7773f5b7f1837351a8945b3f084 100644 (file)
@@ -118,6 +118,9 @@ static int option_inquiry(struct us_data *us)
 
        result = memcmp(buffer+8, "Option", 6);
 
+       if (result != 0)
+               result = memcmp(buffer+8, "ZCOPTION", 8);
+
        /* Read the CSW */
        usb_stor_bulk_transfer_buf(us,
                        us->recv_bulk_pipe,
index fcb320217218109d60147b5bb5dc297f65b96da0..e20dc525d17763642f65a07835a4a2ca462f1a4a 100644 (file)
@@ -961,7 +961,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
                                 US_BULK_GET_MAX_LUN, 
                                 USB_DIR_IN | USB_TYPE_CLASS | 
                                 USB_RECIP_INTERFACE,
-                                0, us->ifnum, us->iobuf, 1, HZ);
+                                0, us->ifnum, us->iobuf, 1, 10*HZ);
 
        US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
                  result, us->iobuf[0]);
index 8afcf08eba9868710366f23058f8793d71034fdc..3b54b39401781a7b42c076b66cad74eab0ff5259 100644 (file)
@@ -1119,12 +1119,13 @@ config FB_CARILLO_RANCH
 
 config FB_INTEL
        tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL
+       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EMBEDDED
        select FB_MODE_HELPERS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select FB_BOOT_VESA_SUPPORT if FB_INTEL = y
+       depends on !DRM_I915
        help
          This driver supports the on-board graphics built in to the Intel
           830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
index cb88394ba9952b8918542981bd39d3d81102cb39..da05f0801bb754221188d15ddcd070e85b796830 100644 (file)
@@ -261,6 +261,9 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
 /**
  *     atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
  *     @sinfo: the frame buffer to allocate memory for
+ *     
+ *     This function is called only from the atmel_lcdfb_probe()
+ *     so no locking by fb_info->mm_lock around smem_len setting is needed.
  */
 static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
 {
@@ -270,9 +273,7 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
 
        smem_len = (var->xres_virtual * var->yres_virtual
                    * ((var->bits_per_pixel + 7) / 8));
-       mutex_lock(&info->mm_lock);
        info->fix.smem_len = max(smem_len, sinfo->smem_len);
-       mutex_unlock(&info->mm_lock);
 
        info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
                                        (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
index e641584e212e64c087cada21136b6840ff18d2e5..88716626744391a89cae97a5658fb3cc0ffbd545 100644 (file)
@@ -145,6 +145,8 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
        struct backlight_device *bl = platform_get_drvdata(pdev);
        struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
+       if (pb->notify)
+               pb->notify(0);
        pwm_config(pb->pwm, 0, pb->period);
        pwm_disable(pb->pwm);
        return 0;
index 53ea05645ff8e8bedb93e354d26f7f945628d8dd..a85c818be9453ecbdf11310b8a77f41435652000 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/compat.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
index 5c1a2c01778fe6e195df9405d0409d7a1a2a09f9..9ae9cd32bd065b1142d63c9975ad51fd1a1972e5 100644 (file)
@@ -256,8 +256,8 @@ static void fix_edid(unsigned char *edid, int fix)
 
 static int edid_checksum(unsigned char *edid)
 {
-       unsigned char i, csum = 0, all_null = 0;
-       int err = 0, fix = check_edid(edid);
+       unsigned char csum = 0, all_null = 0;
+       int i, err = 0, fix = check_edid(edid);
 
        if (fix)
                fix_edid(edid, fix);
index 0bf2190928d0e712e12174cc120e9021a1f869f8..72d68b3dc478ec4292b6eef69025de3d25a43a52 100644 (file)
@@ -1223,12 +1223,6 @@ static int __devinit install_fb(struct fb_info *info)
                return -EINVAL;
        }
 
-       if (fsl_diu_set_par(info)) {
-               printk(KERN_ERR "fb_set_par failed");
-               fb_dealloc_cmap(&info->cmap);
-               return -EINVAL;
-       }
-
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "register_framebuffer failed");
                unmap_video_memory(info);
index 567fb944bd2ae0a5de08d16bf4142a92cf79823c..f8778cde218327aec8666b2e758c3763fb9e06a3 100644 (file)
@@ -1365,11 +1365,6 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
        init_completion(&mx3fbi->flip_cmpl);
        disable_irq(ichan->eof_irq);
        dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);
-       ret = mx3fb_set_par(fbi);
-       if (ret < 0)
-               goto esetpar;
-
-       mx3fb_blank(FB_BLANK_UNBLANK, fbi);
 
        dev_info(dev, "registered, using mode %s\n", fb_mode);
 
index 4ea99bfc37b48447824e373579e3adb571c28dc0..8862233d57b65c0e9d779c680027339a004f7fd8 100644 (file)
@@ -1254,7 +1254,7 @@ static struct fb_ops omapfb_ops = {
 static ssize_t omapfb_show_caps_num(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int plane;
        size_t size;
        struct omapfb_caps caps;
@@ -1274,7 +1274,7 @@ static ssize_t omapfb_show_caps_num(struct device *dev,
 static ssize_t omapfb_show_caps_text(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int i;
        struct omapfb_caps caps;
        int plane;
@@ -1321,7 +1321,7 @@ static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
 static ssize_t omapfb_show_panel_name(struct device *dev,
                                      struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
 }
@@ -1330,7 +1330,7 @@ static ssize_t omapfb_show_bklight_level(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->get_bklight_level) {
@@ -1345,7 +1345,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev,
                                          struct device_attribute *attr,
                                          const char *buf, size_t size)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->set_bklight_level) {
@@ -1364,7 +1364,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev,
 static ssize_t omapfb_show_bklight_max(struct device *dev,
                                       struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
        int r;
 
        if (fbdev->panel->get_bklight_level) {
@@ -1397,7 +1397,7 @@ static struct attribute_group panel_attr_grp = {
 static ssize_t omapfb_show_ctrl_name(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+       struct omapfb_device *fbdev = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
 }
index 16d4f4c7d52b5b02e6fcff002b8c0d03160b371c..924d79462780c5eb34ee79f5dfa0fb61dec193f8 100644 (file)
@@ -1540,9 +1540,6 @@ static int sm501fb_init_fb(struct fb_info *fb,
        if (ret)
                dev_err(info->dev, "check_var() failed on initial setup?\n");
 
-       /* ensure we've activated our new configuration */
-       (fb->fbops->fb_set_par)(fb);
-
        return 0;
 }
 
index 193c8f0e5cc5708a8e1077c0a60bc04c3eaafd2d..bcec78ffc765b67e190d87d5fbf2c35b72e2f0eb 100644 (file)
@@ -669,7 +669,7 @@ static int __init virtio_pci_init(void)
 
        err = pci_register_driver(&virtio_pci_driver);
        if (err)
-               device_unregister(virtio_pci_root);
+               root_device_unregister(virtio_pci_root);
 
        return err;
 }
index 5c7011cda6a6a65e1510022c06a8de3b4420a96b..751c003864ad6df86455248e8542e08578f05125 100644 (file)
@@ -161,7 +161,7 @@ static long bcm47xx_wdt_ioctl(struct file *file,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       int new_value, retval = -EINVAL;;
+       int new_value, retval = -EINVAL;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
index e9f950ff86eaee3e685bd35b4eb9c17221da4cde..cdd55e0d09f8410b949f730fb1cdd6ba07db8ddd 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/watchdog.h>
 #include <linux/timer.h>
 #include <linux/uaccess.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 
 #define WDT_VERSION    "0.3"
index ee1caae4d33b0683fe7e13501493eb933078b745..016245419fadb17eda3646152ab507ae1057440f 100644 (file)
@@ -38,7 +38,7 @@
 
 static unsigned long oscr_freq;
 static unsigned long sa1100wdt_users;
-static int pre_margin;
+static unsigned int pre_margin;
 static int boot_status;
 
 /*
@@ -84,6 +84,7 @@ static const struct watchdog_info ident = {
        .options        = WDIOF_CARDRESET | WDIOF_SETTIMEOUT
                                | WDIOF_KEEPALIVEPING,
        .identity       = "SA1100/PXA255 Watchdog",
+       .firmware_version       = 1,
 };
 
 static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
@@ -118,7 +119,7 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
                if (ret)
                        break;
 
-               if (time <= 0 || time > 255) {
+               if (time <= 0 || (oscr_freq * (long long)time >= 0xffffffff)) {
                        ret = -EINVAL;
                        break;
                }
index 916890abffdd3ca9f9010d90b53319db932fce4c..f201accc4e3d908a00ce91ad029177d0c5315f57 100644 (file)
@@ -89,6 +89,11 @@ static void w83627hf_select_wd_register(void)
                c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
                outb_p(0x2b, WDT_EFER);
                outb_p(c, WDT_EFDR);    /* set GPIO3 to WDT0 */
+       } else if (c == 0x88) { /* W83627EHF */
+               outb_p(0x2d, WDT_EFER); /* select GPIO5 */
+               c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */
+               outb_p(0x2d, WDT_EFER);
+               outb_p(c, WDT_EFDR); /* set GPIO5 to WDT0 */
        }
 
        outb_p(0x07, WDT_EFER); /* point to logical device number reg */
index 883b5f79673a65026f9f129bbe22b79b31bdd652..a6c12dec91a1434c57709b8570f3a3666ae04bc7 100644 (file)
@@ -149,8 +149,10 @@ static void wdt_ctrl(int timeout)
 {
        spin_lock(&io_lock);
 
-       if (w83697ug_select_wd_register() < 0)
+       if (w83697ug_select_wd_register() < 0) {
+               spin_unlock(&io_lock);
                return;
+       }
 
        outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
        outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
index 6fcb1e7095cfe0a97255170656d76e3fe8ed9a30..92828281a30b9a0a449255003d6bf4468fab0512 100644 (file)
@@ -57,7 +57,7 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page)
        buffer = kmap(page);
        offset = page_offset(page);
 
-       retval = v9fs_file_readn(filp, buffer, NULL, offset, PAGE_CACHE_SIZE);
+       retval = v9fs_file_readn(filp, buffer, NULL, PAGE_CACHE_SIZE, offset);
        if (retval < 0)
                goto done;
 
index a97263be6a91d4927bef9dd8c3e834c7c251a472..0e7da7bb5d9351756f691e4ced2e0df2c56a23f6 100644 (file)
@@ -186,32 +186,7 @@ source "fs/romfs/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 source "fs/exofs/Kconfig"
-
-config NILFS2_FS
-       tristate "NILFS2 file system support (EXPERIMENTAL)"
-       depends on BLOCK && EXPERIMENTAL
-       select CRC32
-       help
-         NILFS2 is a log-structured file system (LFS) supporting continuous
-         snapshotting.  In addition to versioning capability of the entire
-         file system, users can even restore files mistakenly overwritten or
-         destroyed just a few seconds ago.  Since this file system can keep
-         consistency like conventional LFS, it achieves quick recovery after
-         system crashes.
-
-         NILFS2 creates a number of checkpoints every few seconds or per
-         synchronous write basis (unless there is no change).  Users can
-         select significant versions among continuously created checkpoints,
-         and can change them into snapshots which will be preserved for long
-         periods until they are changed back to checkpoints.  Each
-         snapshot is mountable as a read-only file system concurrently with
-         its writable mount, and this feature is convenient for online backup.
-
-         Some features including atime, extended attributes, and POSIX ACLs,
-         are not supported yet.
-
-         To compile this file system support as a module, choose M here: the
-         module will be called nilfs2.  If unsure, say N.
+source "fs/nilfs2/Kconfig"
 
 endif # MISC_FILESYSTEMS
 
index aad92f0a1048428e9c02b010471511edcc15e015..6910a98bd73cefc29cc0e8435dfd0949625d34fd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/parser.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/statfs.h>
 #include "adfs.h"
 #include "dir_f.h"
index 9bd757774c9ed0d154b7f8ec55f93db18f08c9bc..88067f36e5e7bea4c4d51cff5dd0a9e24e79b3ad 100644 (file)
@@ -564,7 +564,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct afs_vnode *vnode, *dir;
-       struct afs_fid fid;
+       struct afs_fid uninitialized_var(fid);
        struct dentry *parent;
        struct key *key;
        void *dir_version;
index ad0514d0115f76356ab2aa6034fab3aa2ea79597..e1ea1c240b6a2caa7e6b5220bc02380db0e2dea5 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
index f3da2eb51f56a2c02e579a76517a6547c1ca65e2..00bf8fcb245f13cfd7bab5fcd7bc0fdb92952087 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/sched.h>
 #include <linux/compat.h>
 #include <linux/syscalls.h>
-#include <linux/smp_lock.h>
 #include <linux/magic.h>
 #include <linux/dcache.h>
 #include <linux/uaccess.h>
index 54bd07d44e6875447ebcbfdc47b12bffb5484784..1e41aadb1068672a1969d6496dce9dd5e930b656 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
 #include "bfs.h"
index 6a021265f018e5e42717c9b7001b47fe69a744e9..88b9a3ff44e4bc71bcc15029283dd706f2eaa73a 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include "bfs.h"
 
 #undef DEBUG
index 1486b19fc431560b84c4a8627e229ac359f719c6..76738005c8e8af43c3b084a48d4f752e36e2186d 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
 }
 
 static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
-                         struct sg_iovec *iov, int iov_count, int uncopy,
-                         int do_free_page)
+                         struct sg_iovec *iov, int iov_count,
+                         int to_user, int from_user, int do_free_page)
 {
        int ret = 0, i;
        struct bio_vec *bvec;
        int iov_idx = 0;
        unsigned int iov_off = 0;
-       int read = bio_data_dir(bio) == READ;
 
        __bio_for_each_segment(bvec, bio, i, 0) {
                char *bv_addr = page_address(bvec->bv_page);
@@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
                        iov_addr = iov[iov_idx].iov_base + iov_off;
 
                        if (!ret) {
-                               if (!read && !uncopy)
-                                       ret = copy_from_user(bv_addr, iov_addr,
-                                                            bytes);
-                               if (read && uncopy)
+                               if (to_user)
                                        ret = copy_to_user(iov_addr, bv_addr,
                                                           bytes);
 
+                               if (from_user)
+                                       ret = copy_from_user(bv_addr, iov_addr,
+                                                            bytes);
+
                                if (ret)
                                        ret = -EFAULT;
                        }
@@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio)
 
        if (!bio_flagged(bio, BIO_NULL_MAPPED))
                ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
-                                    bmd->nr_sgvecs, 1, bmd->is_our_pages);
+                                    bmd->nr_sgvecs, bio_data_dir(bio) == READ,
+                                    0, bmd->is_our_pages);
        bio_free_map_data(bmd);
        bio_put(bio);
        return ret;
@@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        /*
         * success
         */
-       if (!write_to_vm && (!map_data || !map_data->null_mapped)) {
-               ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0);
+       if ((!write_to_vm && (!map_data || !map_data->null_mapped)) ||
+           (map_data && map_data->from_user)) {
+               ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0);
                if (ret)
                        goto cleanup;
        }
index 6e4f6c50a120dfcb78eb5f26dc4301936589cd0f..019e8af449abfeb1679c1a20c801d6b0082edf8b 100644 (file)
@@ -424,11 +424,11 @@ int btrfs_requeue_work(struct btrfs_work *work)
         * list
         */
        if (worker->idle) {
-               spin_lock_irqsave(&worker->workers->lock, flags);
+               spin_lock(&worker->workers->lock);
                worker->idle = 0;
                list_move_tail(&worker->worker_list,
                               &worker->workers->worker_list);
-               spin_unlock_irqrestore(&worker->workers->lock, flags);
+               spin_unlock(&worker->workers->lock);
        }
        if (!worker->working) {
                wake = 1;
index de1e2fd32080f0c5c4a835460abf514546c7a6bf..9d8ba4d54a37c3f96e9585de46b8e99d701410bc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
index 60a45f3a4e916fe9af5a8c644b3a8eb9b5b73f81..3fdcc0512d3ab62f95d42708ca0d6a049340b877 100644 (file)
@@ -557,19 +557,7 @@ static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
 
        btrfs_disk_key_to_cpu(&k1, disk);
 
-       if (k1.objectid > k2->objectid)
-               return 1;
-       if (k1.objectid < k2->objectid)
-               return -1;
-       if (k1.type > k2->type)
-               return 1;
-       if (k1.type < k2->type)
-               return -1;
-       if (k1.offset > k2->offset)
-               return 1;
-       if (k1.offset < k2->offset)
-               return -1;
-       return 0;
+       return btrfs_comp_cpu_keys(&k1, k2);
 }
 
 /*
@@ -1052,9 +1040,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
            BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
                return 0;
 
-       if (btrfs_header_nritems(mid) > 2)
-               return 0;
-
        if (btrfs_header_nritems(mid) < 2)
                err_on_enospc = 1;
 
@@ -1701,6 +1686,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        struct extent_buffer *b;
        int slot;
        int ret;
+       int err;
        int level;
        int lowest_unlock = 1;
        u8 lowest_level = 0;
@@ -1737,8 +1723,6 @@ again:
                        p->locks[level] = 1;
 
                if (cow) {
-                       int wret;
-
                        /*
                         * if we don't really need to cow this block
                         * then we don't want to set the path blocking,
@@ -1749,12 +1733,12 @@ again:
 
                        btrfs_set_path_blocking(p);
 
-                       wret = btrfs_cow_block(trans, root, b,
-                                              p->nodes[level + 1],
-                                              p->slots[level + 1], &b);
-                       if (wret) {
+                       err = btrfs_cow_block(trans, root, b,
+                                             p->nodes[level + 1],
+                                             p->slots[level + 1], &b);
+                       if (err) {
                                free_extent_buffer(b);
-                               ret = wret;
+                               ret = err;
                                goto done;
                        }
                }
@@ -1793,41 +1777,45 @@ cow_done:
                ret = bin_search(b, key, level, &slot);
 
                if (level != 0) {
-                       if (ret && slot > 0)
+                       int dec = 0;
+                       if (ret && slot > 0) {
+                               dec = 1;
                                slot -= 1;
+                       }
                        p->slots[level] = slot;
-                       ret = setup_nodes_for_search(trans, root, p, b, level,
+                       err = setup_nodes_for_search(trans, root, p, b, level,
                                                     ins_len);
-                       if (ret == -EAGAIN)
+                       if (err == -EAGAIN)
                                goto again;
-                       else if (ret)
+                       if (err) {
+                               ret = err;
                                goto done;
+                       }
                        b = p->nodes[level];
                        slot = p->slots[level];
 
                        unlock_up(p, level, lowest_unlock);
 
-                       /* this is only true while dropping a snapshot */
                        if (level == lowest_level) {
-                               ret = 0;
+                               if (dec)
+                                       p->slots[level]++;
                                goto done;
                        }
 
-                       ret = read_block_for_search(trans, root, p,
+                       err = read_block_for_search(trans, root, p,
                                                    &b, level, slot, key);
-                       if (ret == -EAGAIN)
+                       if (err == -EAGAIN)
                                goto again;
-
-                       if (ret == -EIO)
+                       if (err) {
+                               ret = err;
                                goto done;
+                       }
 
                        if (!p->skip_locking) {
-                               int lret;
-
                                btrfs_clear_path_blocking(p, NULL);
-                               lret = btrfs_try_spin_lock(b);
+                               err = btrfs_try_spin_lock(b);
 
-                               if (!lret) {
+                               if (!err) {
                                        btrfs_set_path_blocking(p);
                                        btrfs_tree_lock(b);
                                        btrfs_clear_path_blocking(p, b);
@@ -1837,16 +1825,14 @@ cow_done:
                        p->slots[level] = slot;
                        if (ins_len > 0 &&
                            btrfs_leaf_free_space(root, b) < ins_len) {
-                               int sret;
-
                                btrfs_set_path_blocking(p);
-                               sret = split_leaf(trans, root, key,
-                                                     p, ins_len, ret == 0);
+                               err = split_leaf(trans, root, key,
+                                                p, ins_len, ret == 0);
                                btrfs_clear_path_blocking(p, NULL);
 
-                               BUG_ON(sret > 0);
-                               if (sret) {
-                                       ret = sret;
+                               BUG_ON(err > 0);
+                               if (err) {
+                                       ret = err;
                                        goto done;
                                }
                        }
@@ -3807,7 +3793,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                }
 
                /* delete the leaf if it is mostly empty */
-               if (used < BTRFS_LEAF_DATA_SIZE(root) / 2) {
+               if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) {
                        /* push_leaf_left fixes the path.
                         * make sure the path still points to our leaf
                         * for possible call to del_ptr below
@@ -4042,10 +4028,9 @@ out:
  * calling this function.
  */
 int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
-                       struct btrfs_key *key, int lowest_level,
+                       struct btrfs_key *key, int level,
                        int cache_only, u64 min_trans)
 {
-       int level = lowest_level;
        int slot;
        struct extent_buffer *c;
 
@@ -4058,11 +4043,40 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
                c = path->nodes[level];
 next:
                if (slot >= btrfs_header_nritems(c)) {
-                       level++;
-                       if (level == BTRFS_MAX_LEVEL)
+                       int ret;
+                       int orig_lowest;
+                       struct btrfs_key cur_key;
+                       if (level + 1 >= BTRFS_MAX_LEVEL ||
+                           !path->nodes[level + 1])
                                return 1;
-                       continue;
+
+                       if (path->locks[level + 1]) {
+                               level++;
+                               continue;
+                       }
+
+                       slot = btrfs_header_nritems(c) - 1;
+                       if (level == 0)
+                               btrfs_item_key_to_cpu(c, &cur_key, slot);
+                       else
+                               btrfs_node_key_to_cpu(c, &cur_key, slot);
+
+                       orig_lowest = path->lowest_level;
+                       btrfs_release_path(root, path);
+                       path->lowest_level = level;
+                       ret = btrfs_search_slot(NULL, root, &cur_key, path,
+                                               0, 0);
+                       path->lowest_level = orig_lowest;
+                       if (ret < 0)
+                               return ret;
+
+                       c = path->nodes[level];
+                       slot = path->slots[level];
+                       if (ret == 0)
+                               slot++;
+                       goto next;
                }
+
                if (level == 0)
                        btrfs_item_key_to_cpu(c, key, slot);
                else {
@@ -4146,7 +4160,8 @@ again:
         * advance the path if there are now more items available.
         */
        if (nritems > 0 && path->slots[0] < nritems - 1) {
-               path->slots[0]++;
+               if (ret == 0)
+                       path->slots[0]++;
                ret = 0;
                goto done;
        }
@@ -4278,10 +4293,10 @@ int btrfs_previous_item(struct btrfs_root *root,
                        path->slots[0]--;
 
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (found_key.type == type)
-                       return 0;
                if (found_key.objectid < min_objectid)
                        break;
+               if (found_key.type == type)
+                       return 0;
                if (found_key.objectid == min_objectid &&
                    found_key.type < type)
                        break;
index 98a87383871722fbddc36590cae9e60a512ef53a..215ef8cae823ce53cf91e559ebfe7ed602eda214 100644 (file)
@@ -481,7 +481,7 @@ struct btrfs_shared_data_ref {
 
 struct btrfs_extent_inline_ref {
        u8 type;
-       u64 offset;
+       __le64 offset;
 } __attribute__ ((__packed__));
 
 /* old style backrefs item */
@@ -689,6 +689,7 @@ struct btrfs_space_info {
        struct list_head block_groups;
        spinlock_t lock;
        struct rw_semaphore groups_sem;
+       atomic_t caching_threads;
 };
 
 /*
@@ -707,6 +708,9 @@ struct btrfs_free_cluster {
        /* first extent starting offset */
        u64 window_start;
 
+       /* if this cluster simply points at a bitmap in the block group */
+       bool points_to_bitmap;
+
        struct btrfs_block_group_cache *block_group;
        /*
         * when a cluster is allocated from a block group, we put the
@@ -716,24 +720,37 @@ struct btrfs_free_cluster {
        struct list_head block_group_list;
 };
 
+enum btrfs_caching_type {
+       BTRFS_CACHE_NO          = 0,
+       BTRFS_CACHE_STARTED     = 1,
+       BTRFS_CACHE_FINISHED    = 2,
+};
+
 struct btrfs_block_group_cache {
        struct btrfs_key key;
        struct btrfs_block_group_item item;
+       struct btrfs_fs_info *fs_info;
        spinlock_t lock;
-       struct mutex cache_mutex;
        u64 pinned;
        u64 reserved;
        u64 flags;
-       int cached;
+       u64 sectorsize;
+       int extents_thresh;
+       int free_extents;
+       int total_bitmaps;
        int ro;
        int dirty;
 
+       /* cache tracking stuff */
+       wait_queue_head_t caching_q;
+       int cached;
+
        struct btrfs_space_info *space_info;
 
        /* free space cache stuff */
        spinlock_t tree_lock;
-       struct rb_root free_space_bytes;
        struct rb_root free_space_offset;
+       u64 free_space;
 
        /* block group cache stuff */
        struct rb_node cache_node;
@@ -942,6 +959,9 @@ struct btrfs_root {
        /* the node lock is held while changing the node pointer */
        spinlock_t node_lock;
 
+       /* taken when updating the commit root */
+       struct rw_semaphore commit_root_sem;
+
        struct extent_buffer *commit_root;
        struct btrfs_root *log_root;
        struct btrfs_root *reloc_root;
@@ -1988,6 +2008,7 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
                                 u64 bytes);
 void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
                              u64 bytes);
+void btrfs_free_pinned_extents(struct btrfs_fs_info *info);
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
                     int level, int *slot);
index d28d29c95f7ca23a91e9ccf3c306840484ea29ed..7dcaa8138864b455ea0314bcf78d17fe820c2f5d 100644 (file)
@@ -909,6 +909,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        spin_lock_init(&root->inode_lock);
        mutex_init(&root->objectid_mutex);
        mutex_init(&root->log_mutex);
+       init_rwsem(&root->commit_root_sem);
        init_waitqueue_head(&root->log_writer_wait);
        init_waitqueue_head(&root->log_commit_wait[0]);
        init_waitqueue_head(&root->log_commit_wait[1]);
@@ -1799,6 +1800,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                                           btrfs_super_chunk_root(disk_super),
                                           blocksize, generation);
        BUG_ON(!chunk_root->node);
+       if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
+               printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
+                      sb->s_id);
+               goto fail_chunk_root;
+       }
        btrfs_set_root_node(&chunk_root->root_item, chunk_root->node);
        chunk_root->commit_root = btrfs_root_node(chunk_root);
 
@@ -1826,6 +1832,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                                          blocksize, generation);
        if (!tree_root->node)
                goto fail_chunk_root;
+       if (!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) {
+               printk(KERN_WARNING "btrfs: failed to read tree root on %s\n",
+                      sb->s_id);
+               goto fail_tree_root;
+       }
        btrfs_set_root_node(&tree_root->root_item, tree_root->node);
        tree_root->commit_root = btrfs_root_node(tree_root);
 
@@ -2322,6 +2333,9 @@ int close_ctree(struct btrfs_root *root)
                        printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
        }
 
+       fs_info->closing = 2;
+       smp_mb();
+
        if (fs_info->delalloc_bytes) {
                printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
                       (unsigned long long)fs_info->delalloc_bytes);
@@ -2343,6 +2357,7 @@ int close_ctree(struct btrfs_root *root)
        free_extent_buffer(root->fs_info->csum_root->commit_root);
 
        btrfs_free_block_groups(root->fs_info);
+       btrfs_free_pinned_extents(root->fs_info);
 
        del_fs_roots(fs_info);
 
index a5aca3997d426da09c87e33642916284eca135b6..fadf69a2764b316828f82d31be8490c0dcf57739 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/blkdev.h>
 #include <linux/sort.h>
 #include <linux/rcupdate.h>
+#include <linux/kthread.h>
 #include "compat.h"
 #include "hash.h"
 #include "ctree.h"
@@ -61,6 +62,13 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
                          u64 flags, int force);
 
+static noinline int
+block_group_cache_done(struct btrfs_block_group_cache *cache)
+{
+       smp_mb();
+       return cache->cached == BTRFS_CACHE_FINISHED;
+}
+
 static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
 {
        return (cache->flags & bits) == bits;
@@ -145,21 +153,71 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr,
        return ret;
 }
 
+/*
+ * We always set EXTENT_LOCKED for the super mirror extents so we don't
+ * overwrite them, so those bits need to be unset.  Also, if we are unmounting
+ * with pinned extents still sitting there because we had a block group caching,
+ * we need to clear those now, since we are done.
+ */
+void btrfs_free_pinned_extents(struct btrfs_fs_info *info)
+{
+       u64 start, end, last = 0;
+       int ret;
+
+       while (1) {
+               ret = find_first_extent_bit(&info->pinned_extents, last,
+                                           &start, &end,
+                                           EXTENT_LOCKED|EXTENT_DIRTY);
+               if (ret)
+                       break;
+
+               clear_extent_bits(&info->pinned_extents, start, end,
+                                 EXTENT_LOCKED|EXTENT_DIRTY, GFP_NOFS);
+               last = end+1;
+       }
+}
+
+static int remove_sb_from_cache(struct btrfs_root *root,
+                               struct btrfs_block_group_cache *cache)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u64 bytenr;
+       u64 *logical;
+       int stripe_len;
+       int i, nr, ret;
+
+       for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+               bytenr = btrfs_sb_offset(i);
+               ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
+                                      cache->key.objectid, bytenr,
+                                      0, &logical, &nr, &stripe_len);
+               BUG_ON(ret);
+               while (nr--) {
+                       try_lock_extent(&fs_info->pinned_extents,
+                                       logical[nr],
+                                       logical[nr] + stripe_len - 1, GFP_NOFS);
+               }
+               kfree(logical);
+       }
+
+       return 0;
+}
+
 /*
  * this is only called by cache_block_group, since we could have freed extents
  * we need to check the pinned_extents for any extents that can't be used yet
  * since their free space will be released as soon as the transaction commits.
  */
-static int add_new_free_space(struct btrfs_block_group_cache *block_group,
+static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
                              struct btrfs_fs_info *info, u64 start, u64 end)
 {
-       u64 extent_start, extent_end, size;
+       u64 extent_start, extent_end, size, total_added = 0;
        int ret;
 
        while (start < end) {
                ret = find_first_extent_bit(&info->pinned_extents, start,
                                            &extent_start, &extent_end,
-                                           EXTENT_DIRTY);
+                                           EXTENT_DIRTY|EXTENT_LOCKED);
                if (ret)
                        break;
 
@@ -167,6 +225,7 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
                        start = extent_end + 1;
                } else if (extent_start > start && extent_start < end) {
                        size = extent_start - start;
+                       total_added += size;
                        ret = btrfs_add_free_space(block_group, start,
                                                   size);
                        BUG_ON(ret);
@@ -178,84 +237,79 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
 
        if (start < end) {
                size = end - start;
+               total_added += size;
                ret = btrfs_add_free_space(block_group, start, size);
                BUG_ON(ret);
        }
 
-       return 0;
+       return total_added;
 }
 
-static int remove_sb_from_cache(struct btrfs_root *root,
-                               struct btrfs_block_group_cache *cache)
-{
-       u64 bytenr;
-       u64 *logical;
-       int stripe_len;
-       int i, nr, ret;
-
-       for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
-               bytenr = btrfs_sb_offset(i);
-               ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
-                                      cache->key.objectid, bytenr, 0,
-                                      &logical, &nr, &stripe_len);
-               BUG_ON(ret);
-               while (nr--) {
-                       btrfs_remove_free_space(cache, logical[nr],
-                                               stripe_len);
-               }
-               kfree(logical);
-       }
-       return 0;
-}
-
-static int cache_block_group(struct btrfs_root *root,
-                            struct btrfs_block_group_cache *block_group)
+static int caching_kthread(void *data)
 {
+       struct btrfs_block_group_cache *block_group = data;
+       struct btrfs_fs_info *fs_info = block_group->fs_info;
+       u64 last = 0;
        struct btrfs_path *path;
        int ret = 0;
        struct btrfs_key key;
        struct extent_buffer *leaf;
        int slot;
-       u64 last;
-
-       if (!block_group)
-               return 0;
+       u64 total_found = 0;
 
-       root = root->fs_info->extent_root;
-
-       if (block_group->cached)
-               return 0;
+       BUG_ON(!fs_info);
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       path->reada = 2;
+       atomic_inc(&block_group->space_info->caching_threads);
+       last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
+again:
+       /* need to make sure the commit_root doesn't disappear */
+       down_read(&fs_info->extent_root->commit_root_sem);
+
        /*
-        * we get into deadlocks with paths held by callers of this function.
-        * since the alloc_mutex is protecting things right now, just
-        * skip the locking here
+        * We don't want to deadlock with somebody trying to allocate a new
+        * extent for the extent root while also trying to search the extent
+        * root to add free space.  So we skip locking and search the commit
+        * root, since its read-only
         */
        path->skip_locking = 1;
-       last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
+       path->search_commit_root = 1;
+       path->reada = 2;
+
        key.objectid = last;
        key.offset = 0;
        btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
-       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
        if (ret < 0)
                goto err;
 
        while (1) {
+               smp_mb();
+               if (block_group->fs_info->closing > 1) {
+                       last = (u64)-1;
+                       break;
+               }
+
                leaf = path->nodes[0];
                slot = path->slots[0];
                if (slot >= btrfs_header_nritems(leaf)) {
-                       ret = btrfs_next_leaf(root, path);
+                       ret = btrfs_next_leaf(fs_info->extent_root, path);
                        if (ret < 0)
                                goto err;
-                       if (ret == 0)
-                               continue;
-                       else
+                       else if (ret)
                                break;
+
+                       if (need_resched()) {
+                               btrfs_release_path(fs_info->extent_root, path);
+                               up_read(&fs_info->extent_root->commit_root_sem);
+                               cond_resched();
+                               goto again;
+                       }
+
+                       continue;
                }
                btrfs_item_key_to_cpu(leaf, &key, slot);
                if (key.objectid < block_group->key.objectid)
@@ -266,24 +320,59 @@ static int cache_block_group(struct btrfs_root *root,
                        break;
 
                if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
-                       add_new_free_space(block_group, root->fs_info, last,
-                                          key.objectid);
-
+                       total_found += add_new_free_space(block_group,
+                                                         fs_info, last,
+                                                         key.objectid);
                        last = key.objectid + key.offset;
                }
+
+               if (total_found > (1024 * 1024 * 2)) {
+                       total_found = 0;
+                       wake_up(&block_group->caching_q);
+               }
 next:
                path->slots[0]++;
        }
+       ret = 0;
 
-       add_new_free_space(block_group, root->fs_info, last,
-                          block_group->key.objectid +
-                          block_group->key.offset);
+       total_found += add_new_free_space(block_group, fs_info, last,
+                                         block_group->key.objectid +
+                                         block_group->key.offset);
+
+       spin_lock(&block_group->lock);
+       block_group->cached = BTRFS_CACHE_FINISHED;
+       spin_unlock(&block_group->lock);
 
-       block_group->cached = 1;
-       remove_sb_from_cache(root, block_group);
-       ret = 0;
 err:
        btrfs_free_path(path);
+       up_read(&fs_info->extent_root->commit_root_sem);
+       atomic_dec(&block_group->space_info->caching_threads);
+       wake_up(&block_group->caching_q);
+
+       return 0;
+}
+
+static int cache_block_group(struct btrfs_block_group_cache *cache)
+{
+       struct task_struct *tsk;
+       int ret = 0;
+
+       spin_lock(&cache->lock);
+       if (cache->cached != BTRFS_CACHE_NO) {
+               spin_unlock(&cache->lock);
+               return ret;
+       }
+       cache->cached = BTRFS_CACHE_STARTED;
+       spin_unlock(&cache->lock);
+
+       tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n",
+                         cache->key.objectid);
+       if (IS_ERR(tsk)) {
+               ret = PTR_ERR(tsk);
+               printk(KERN_ERR "error running thread %d\n", ret);
+               BUG();
+       }
+
        return ret;
 }
 
@@ -2387,13 +2476,29 @@ fail:
 
 }
 
+static struct btrfs_block_group_cache *
+next_block_group(struct btrfs_root *root,
+                struct btrfs_block_group_cache *cache)
+{
+       struct rb_node *node;
+       spin_lock(&root->fs_info->block_group_cache_lock);
+       node = rb_next(&cache->cache_node);
+       btrfs_put_block_group(cache);
+       if (node) {
+               cache = rb_entry(node, struct btrfs_block_group_cache,
+                                cache_node);
+               atomic_inc(&cache->count);
+       } else
+               cache = NULL;
+       spin_unlock(&root->fs_info->block_group_cache_lock);
+       return cache;
+}
+
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
-       struct btrfs_block_group_cache *cache, *entry;
-       struct rb_node *n;
+       struct btrfs_block_group_cache *cache;
        int err = 0;
-       int werr = 0;
        struct btrfs_path *path;
        u64 last = 0;
 
@@ -2402,39 +2507,35 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        while (1) {
-               cache = NULL;
-               spin_lock(&root->fs_info->block_group_cache_lock);
-               for (n = rb_first(&root->fs_info->block_group_cache_tree);
-                    n; n = rb_next(n)) {
-                       entry = rb_entry(n, struct btrfs_block_group_cache,
-                                        cache_node);
-                       if (entry->dirty) {
-                               cache = entry;
-                               break;
-                       }
+               if (last == 0) {
+                       err = btrfs_run_delayed_refs(trans, root,
+                                                    (unsigned long)-1);
+                       BUG_ON(err);
                }
-               spin_unlock(&root->fs_info->block_group_cache_lock);
 
-               if (!cache)
-                       break;
+               cache = btrfs_lookup_first_block_group(root->fs_info, last);
+               while (cache) {
+                       if (cache->dirty)
+                               break;
+                       cache = next_block_group(root, cache);
+               }
+               if (!cache) {
+                       if (last == 0)
+                               break;
+                       last = 0;
+                       continue;
+               }
 
                cache->dirty = 0;
-               last += cache->key.offset;
+               last = cache->key.objectid + cache->key.offset;
 
-               err = write_one_cache_group(trans, root,
-                                           path, cache);
-               /*
-                * if we fail to write the cache group, we want
-                * to keep it marked dirty in hopes that a later
-                * write will work
-                */
-               if (err) {
-                       werr = err;
-                       continue;
-               }
+               err = write_one_cache_group(trans, root, path, cache);
+               BUG_ON(err);
+               btrfs_put_block_group(cache);
        }
+
        btrfs_free_path(path);
-       return werr;
+       return 0;
 }
 
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
@@ -2484,6 +2585,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->force_alloc = 0;
        *space_info = found;
        list_add_rcu(&found->list, &info->space_info);
+       atomic_set(&found->caching_threads, 0);
        return 0;
 }
 
@@ -2947,13 +3049,9 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
        struct btrfs_block_group_cache *cache;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       if (pin) {
+       if (pin)
                set_extent_dirty(&fs_info->pinned_extents,
                                bytenr, bytenr + num - 1, GFP_NOFS);
-       } else {
-               clear_extent_dirty(&fs_info->pinned_extents,
-                               bytenr, bytenr + num - 1, GFP_NOFS);
-       }
 
        while (num > 0) {
                cache = btrfs_lookup_block_group(fs_info, bytenr);
@@ -2969,14 +3067,34 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
                        spin_unlock(&cache->space_info->lock);
                        fs_info->total_pinned += len;
                } else {
+                       int unpin = 0;
+
+                       /*
+                        * in order to not race with the block group caching, we
+                        * only want to unpin the extent if we are cached.  If
+                        * we aren't cached, we want to start async caching this
+                        * block group so we can free the extent the next time
+                        * around.
+                        */
                        spin_lock(&cache->space_info->lock);
                        spin_lock(&cache->lock);
-                       cache->pinned -= len;
-                       cache->space_info->bytes_pinned -= len;
+                       unpin = (cache->cached == BTRFS_CACHE_FINISHED);
+                       if (likely(unpin)) {
+                               cache->pinned -= len;
+                               cache->space_info->bytes_pinned -= len;
+                               fs_info->total_pinned -= len;
+                       }
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
-                       fs_info->total_pinned -= len;
-                       if (cache->cached)
+
+                       if (likely(unpin))
+                               clear_extent_dirty(&fs_info->pinned_extents,
+                                                  bytenr, bytenr + len -1,
+                                                  GFP_NOFS);
+                       else
+                               cache_block_group(cache);
+
+                       if (unpin)
                                btrfs_add_free_space(cache, bytenr, len);
                }
                btrfs_put_block_group(cache);
@@ -3030,6 +3148,7 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy)
                                            &start, &end, EXTENT_DIRTY);
                if (ret)
                        break;
+
                set_extent_dirty(copy, start, end, GFP_NOFS);
                last = end + 1;
        }
@@ -3058,6 +3177,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 
                cond_resched();
        }
+
        return ret;
 }
 
@@ -3435,6 +3555,45 @@ static u64 stripe_align(struct btrfs_root *root, u64 val)
        return ret;
 }
 
+/*
+ * when we wait for progress in the block group caching, its because
+ * our allocation attempt failed at least once.  So, we must sleep
+ * and let some progress happen before we try again.
+ *
+ * This function will sleep at least once waiting for new free space to
+ * show up, and then it will check the block group free space numbers
+ * for our min num_bytes.  Another option is to have it go ahead
+ * and look in the rbtree for a free extent of a given size, but this
+ * is a good start.
+ */
+static noinline int
+wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
+                               u64 num_bytes)
+{
+       DEFINE_WAIT(wait);
+
+       prepare_to_wait(&cache->caching_q, &wait, TASK_UNINTERRUPTIBLE);
+
+       if (block_group_cache_done(cache)) {
+               finish_wait(&cache->caching_q, &wait);
+               return 0;
+       }
+       schedule();
+       finish_wait(&cache->caching_q, &wait);
+
+       wait_event(cache->caching_q, block_group_cache_done(cache) ||
+                  (cache->free_space >= num_bytes));
+       return 0;
+}
+
+enum btrfs_loop_type {
+       LOOP_CACHED_ONLY = 0,
+       LOOP_CACHING_NOWAIT = 1,
+       LOOP_CACHING_WAIT = 2,
+       LOOP_ALLOC_CHUNK = 3,
+       LOOP_NO_EMPTY_SIZE = 4,
+};
+
 /*
  * walks the btree of allocated extents and find a hole of a given size.
  * The key ins is changed to record the hole:
@@ -3460,6 +3619,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        struct btrfs_space_info *space_info;
        int last_ptr_loop = 0;
        int loop = 0;
+       bool found_uncached_bg = false;
 
        WARN_ON(num_bytes < root->sectorsize);
        btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -3491,15 +3651,18 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        search_start = max(search_start, first_logical_byte(root, 0));
        search_start = max(search_start, hint_byte);
 
-       if (!last_ptr) {
+       if (!last_ptr)
                empty_cluster = 0;
-               loop = 1;
-       }
 
        if (search_start == hint_byte) {
                block_group = btrfs_lookup_block_group(root->fs_info,
                                                       search_start);
-               if (block_group && block_group_bits(block_group, data)) {
+               /*
+                * we don't want to use the block group if it doesn't match our
+                * allocation bits, or if its not cached.
+                */
+               if (block_group && block_group_bits(block_group, data) &&
+                   block_group_cache_done(block_group)) {
                        down_read(&space_info->groups_sem);
                        if (list_empty(&block_group->list) ||
                            block_group->ro) {
@@ -3522,21 +3685,35 @@ search:
        down_read(&space_info->groups_sem);
        list_for_each_entry(block_group, &space_info->block_groups, list) {
                u64 offset;
+               int cached;
 
                atomic_inc(&block_group->count);
                search_start = block_group->key.objectid;
 
 have_block_group:
-               if (unlikely(!block_group->cached)) {
-                       mutex_lock(&block_group->cache_mutex);
-                       ret = cache_block_group(root, block_group);
-                       mutex_unlock(&block_group->cache_mutex);
-                       if (ret) {
-                               btrfs_put_block_group(block_group);
-                               break;
+               if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
+                       /*
+                        * we want to start caching kthreads, but not too many
+                        * right off the bat so we don't overwhelm the system,
+                        * so only start them if there are less than 2 and we're
+                        * in the initial allocation phase.
+                        */
+                       if (loop > LOOP_CACHING_NOWAIT ||
+                           atomic_read(&space_info->caching_threads) < 2) {
+                               ret = cache_block_group(block_group);
+                               BUG_ON(ret);
                        }
                }
 
+               cached = block_group_cache_done(block_group);
+               if (unlikely(!cached)) {
+                       found_uncached_bg = true;
+
+                       /* if we only want cached bgs, loop */
+                       if (loop == LOOP_CACHED_ONLY)
+                               goto loop;
+               }
+
                if (unlikely(block_group->ro))
                        goto loop;
 
@@ -3615,14 +3792,21 @@ refill_cluster:
                                        spin_unlock(&last_ptr->refill_lock);
                                        goto checks;
                                }
+                       } else if (!cached && loop > LOOP_CACHING_NOWAIT) {
+                               spin_unlock(&last_ptr->refill_lock);
+
+                               wait_block_group_cache_progress(block_group,
+                                      num_bytes + empty_cluster + empty_size);
+                               goto have_block_group;
                        }
+
                        /*
                         * at this point we either didn't find a cluster
                         * or we weren't able to allocate a block from our
                         * cluster.  Free the cluster we've been trying
                         * to use, and go to the next block group
                         */
-                       if (loop < 2) {
+                       if (loop < LOOP_NO_EMPTY_SIZE) {
                                btrfs_return_cluster_to_free_space(NULL,
                                                                   last_ptr);
                                spin_unlock(&last_ptr->refill_lock);
@@ -3633,11 +3817,17 @@ refill_cluster:
 
                offset = btrfs_find_space_for_alloc(block_group, search_start,
                                                    num_bytes, empty_size);
-               if (!offset)
+               if (!offset && (cached || (!cached &&
+                                          loop == LOOP_CACHING_NOWAIT))) {
                        goto loop;
+               } else if (!offset && (!cached &&
+                                      loop > LOOP_CACHING_NOWAIT)) {
+                       wait_block_group_cache_progress(block_group,
+                                       num_bytes + empty_size);
+                       goto have_block_group;
+               }
 checks:
                search_start = stripe_align(root, offset);
-
                /* move on to the next group */
                if (search_start + num_bytes >= search_end) {
                        btrfs_add_free_space(block_group, offset, num_bytes);
@@ -3683,13 +3873,26 @@ loop:
        }
        up_read(&space_info->groups_sem);
 
-       /* loop == 0, try to find a clustered alloc in every block group
-        * loop == 1, try again after forcing a chunk allocation
-        * loop == 2, set empty_size and empty_cluster to 0 and try again
+       /* LOOP_CACHED_ONLY, only search fully cached block groups
+        * LOOP_CACHING_NOWAIT, search partially cached block groups, but
+        *                      dont wait foR them to finish caching
+        * LOOP_CACHING_WAIT, search everything, and wait if our bg is caching
+        * LOOP_ALLOC_CHUNK, force a chunk allocation and try again
+        * LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try
+        *                      again
         */
-       if (!ins->objectid && loop < 3 &&
-           (empty_size || empty_cluster || allowed_chunk_alloc)) {
-               if (loop >= 2) {
+       if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE &&
+           (found_uncached_bg || empty_size || empty_cluster ||
+            allowed_chunk_alloc)) {
+               if (found_uncached_bg) {
+                       found_uncached_bg = false;
+                       if (loop < LOOP_CACHING_WAIT) {
+                               loop++;
+                               goto search;
+                       }
+               }
+
+               if (loop == LOOP_ALLOC_CHUNK) {
                        empty_size = 0;
                        empty_cluster = 0;
                }
@@ -3702,7 +3905,7 @@ loop:
                        space_info->force_alloc = 1;
                }
 
-               if (loop < 3) {
+               if (loop < LOOP_NO_EMPTY_SIZE) {
                        loop++;
                        goto search;
                }
@@ -3798,7 +4001,7 @@ again:
                               num_bytes, data, 1);
                goto again;
        }
-       if (ret) {
+       if (ret == -ENOSPC) {
                struct btrfs_space_info *sinfo;
 
                sinfo = __find_space_info(root->fs_info, data);
@@ -3806,7 +4009,6 @@ again:
                       "wanted %llu\n", (unsigned long long)data,
                       (unsigned long long)num_bytes);
                dump_space_info(sinfo, num_bytes);
-               BUG();
        }
 
        return ret;
@@ -3844,7 +4046,9 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
        ret = __btrfs_reserve_extent(trans, root, num_bytes, min_alloc_size,
                                     empty_size, hint_byte, search_end, ins,
                                     data);
-       update_reserved_extents(root, ins->objectid, ins->offset, 1);
+       if (!ret)
+               update_reserved_extents(root, ins->objectid, ins->offset, 1);
+
        return ret;
 }
 
@@ -4006,9 +4210,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
        struct btrfs_block_group_cache *block_group;
 
        block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
-       mutex_lock(&block_group->cache_mutex);
-       cache_block_group(root, block_group);
-       mutex_unlock(&block_group->cache_mutex);
+       cache_block_group(block_group);
+       wait_event(block_group->caching_q,
+                  block_group_cache_done(block_group));
 
        ret = btrfs_remove_free_space(block_group, ins->objectid,
                                      ins->offset);
@@ -4039,7 +4243,8 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
        ret = __btrfs_reserve_extent(trans, root, num_bytes, num_bytes,
                                     empty_size, hint_byte, search_end,
                                     ins, 0);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
                if (parent == 0)
@@ -6955,11 +7160,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                         &info->block_group_cache_tree);
                spin_unlock(&info->block_group_cache_lock);
 
-               btrfs_remove_free_space_cache(block_group);
                down_write(&block_group->space_info->groups_sem);
                list_del(&block_group->list);
                up_write(&block_group->space_info->groups_sem);
 
+               if (block_group->cached == BTRFS_CACHE_STARTED)
+                       wait_event(block_group->caching_q,
+                                  block_group_cache_done(block_group));
+
+               btrfs_remove_free_space_cache(block_group);
+
                WARN_ON(atomic_read(&block_group->count) != 1);
                kfree(block_group);
 
@@ -7025,9 +7235,19 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                atomic_set(&cache->count, 1);
                spin_lock_init(&cache->lock);
                spin_lock_init(&cache->tree_lock);
-               mutex_init(&cache->cache_mutex);
+               cache->fs_info = info;
+               init_waitqueue_head(&cache->caching_q);
                INIT_LIST_HEAD(&cache->list);
                INIT_LIST_HEAD(&cache->cluster_list);
+
+               /*
+                * we only want to have 32k of ram per block group for keeping
+                * track of free space, and if we pass 1/2 of that we want to
+                * start converting things over to using bitmaps
+                */
+               cache->extents_thresh = ((1024 * 32) / 2) /
+                       sizeof(struct btrfs_free_space);
+
                read_extent_buffer(leaf, &cache->item,
                                   btrfs_item_ptr_offset(leaf, path->slots[0]),
                                   sizeof(cache->item));
@@ -7036,6 +7256,26 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                key.objectid = found_key.objectid + found_key.offset;
                btrfs_release_path(root, path);
                cache->flags = btrfs_block_group_flags(&cache->item);
+               cache->sectorsize = root->sectorsize;
+
+               remove_sb_from_cache(root, cache);
+
+               /*
+                * check for two cases, either we are full, and therefore
+                * don't need to bother with the caching work since we won't
+                * find any space, or we are empty, and we can just add all
+                * the space in and be done with it.  This saves us _alot_ of
+                * time, particularly in the full case.
+                */
+               if (found_key.offset == btrfs_block_group_used(&cache->item)) {
+                       cache->cached = BTRFS_CACHE_FINISHED;
+               } else if (btrfs_block_group_used(&cache->item) == 0) {
+                       cache->cached = BTRFS_CACHE_FINISHED;
+                       add_new_free_space(cache, root->fs_info,
+                                          found_key.objectid,
+                                          found_key.objectid +
+                                          found_key.offset);
+               }
 
                ret = update_space_info(info, cache->flags, found_key.offset,
                                        btrfs_block_group_used(&cache->item),
@@ -7079,10 +7319,19 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        cache->key.objectid = chunk_offset;
        cache->key.offset = size;
        cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+       cache->sectorsize = root->sectorsize;
+
+       /*
+        * we only want to have 32k of ram per block group for keeping track
+        * of free space, and if we pass 1/2 of that we want to start
+        * converting things over to using bitmaps
+        */
+       cache->extents_thresh = ((1024 * 32) / 2) /
+               sizeof(struct btrfs_free_space);
        atomic_set(&cache->count, 1);
        spin_lock_init(&cache->lock);
        spin_lock_init(&cache->tree_lock);
-       mutex_init(&cache->cache_mutex);
+       init_waitqueue_head(&cache->caching_q);
        INIT_LIST_HEAD(&cache->list);
        INIT_LIST_HEAD(&cache->cluster_list);
 
@@ -7091,6 +7340,12 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        cache->flags = type;
        btrfs_set_block_group_flags(&cache->item, type);
 
+       cache->cached = BTRFS_CACHE_FINISHED;
+       remove_sb_from_cache(root, cache);
+
+       add_new_free_space(cache, root->fs_info, chunk_offset,
+                          chunk_offset + size);
+
        ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
                                &cache->space_info);
        BUG_ON(ret);
@@ -7149,7 +7404,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        rb_erase(&block_group->cache_node,
                 &root->fs_info->block_group_cache_tree);
        spin_unlock(&root->fs_info->block_group_cache_lock);
-       btrfs_remove_free_space_cache(block_group);
+
        down_write(&block_group->space_info->groups_sem);
        /*
         * we must use list_del_init so people can check to see if they
@@ -7158,11 +7413,18 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        list_del_init(&block_group->list);
        up_write(&block_group->space_info->groups_sem);
 
+       if (block_group->cached == BTRFS_CACHE_STARTED)
+               wait_event(block_group->caching_q,
+                          block_group_cache_done(block_group));
+
+       btrfs_remove_free_space_cache(block_group);
+
        spin_lock(&block_group->space_info->lock);
        block_group->space_info->total_bytes -= block_group->key.offset;
        block_group->space_info->bytes_readonly -= block_group->key.offset;
        spin_unlock(&block_group->space_info->lock);
-       block_group->space_info->full = 0;
+
+       btrfs_clear_space_info_full(root->fs_info);
 
        btrfs_put_block_group(block_group);
        btrfs_put_block_group(block_group);
index 7c3cd248d8d6151ce5a89d876c2541b2abf73179..4b833972273a75218eb775cf8caf64dc1be80ed7 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
index 4538e48581a5171b33af2d3d2c632dbff4e412e2..af99b78b288e8c5e8a14e44b27b3005e5676c26c 100644 (file)
  * Boston, MA 021110-1307, USA.
  */
 
+#include <linux/pagemap.h>
 #include <linux/sched.h>
+#include <linux/math64.h>
 #include "ctree.h"
 #include "free-space-cache.h"
 #include "transaction.h"
 
-struct btrfs_free_space {
-       struct rb_node bytes_index;
-       struct rb_node offset_index;
-       u64 offset;
-       u64 bytes;
-};
+#define BITS_PER_BITMAP                (PAGE_CACHE_SIZE * 8)
+#define MAX_CACHE_BYTES_PER_GIG        (32 * 1024)
 
-static int tree_insert_offset(struct rb_root *root, u64 offset,
-                             struct rb_node *node)
+static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize,
+                                         u64 offset)
 {
-       struct rb_node **p = &root->rb_node;
-       struct rb_node *parent = NULL;
-       struct btrfs_free_space *info;
+       BUG_ON(offset < bitmap_start);
+       offset -= bitmap_start;
+       return (unsigned long)(div64_u64(offset, sectorsize));
+}
 
-       while (*p) {
-               parent = *p;
-               info = rb_entry(parent, struct btrfs_free_space, offset_index);
+static inline unsigned long bytes_to_bits(u64 bytes, u64 sectorsize)
+{
+       return (unsigned long)(div64_u64(bytes, sectorsize));
+}
 
-               if (offset < info->offset)
-                       p = &(*p)->rb_left;
-               else if (offset > info->offset)
-                       p = &(*p)->rb_right;
-               else
-                       return -EEXIST;
-       }
+static inline u64 offset_to_bitmap(struct btrfs_block_group_cache *block_group,
+                                  u64 offset)
+{
+       u64 bitmap_start;
+       u64 bytes_per_bitmap;
 
-       rb_link_node(node, parent, p);
-       rb_insert_color(node, root);
+       bytes_per_bitmap = BITS_PER_BITMAP * block_group->sectorsize;
+       bitmap_start = offset - block_group->key.objectid;
+       bitmap_start = div64_u64(bitmap_start, bytes_per_bitmap);
+       bitmap_start *= bytes_per_bitmap;
+       bitmap_start += block_group->key.objectid;
 
-       return 0;
+       return bitmap_start;
 }
 
-static int tree_insert_bytes(struct rb_root *root, u64 bytes,
-                            struct rb_node *node)
+static int tree_insert_offset(struct rb_root *root, u64 offset,
+                             struct rb_node *node, int bitmap)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
@@ -62,12 +63,34 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
 
        while (*p) {
                parent = *p;
-               info = rb_entry(parent, struct btrfs_free_space, bytes_index);
+               info = rb_entry(parent, struct btrfs_free_space, offset_index);
 
-               if (bytes < info->bytes)
+               if (offset < info->offset) {
                        p = &(*p)->rb_left;
-               else
+               } else if (offset > info->offset) {
                        p = &(*p)->rb_right;
+               } else {
+                       /*
+                        * we could have a bitmap entry and an extent entry
+                        * share the same offset.  If this is the case, we want
+                        * the extent entry to always be found first if we do a
+                        * linear search through the tree, since we want to have
+                        * the quickest allocation time, and allocating from an
+                        * extent is faster than allocating from a bitmap.  So
+                        * if we're inserting a bitmap and we find an entry at
+                        * this offset, we want to go right, or after this entry
+                        * logically.  If we are inserting an extent and we've
+                        * found a bitmap, we want to go left, or before
+                        * logically.
+                        */
+                       if (bitmap) {
+                               WARN_ON(info->bitmap);
+                               p = &(*p)->rb_right;
+                       } else {
+                               WARN_ON(!info->bitmap);
+                               p = &(*p)->rb_left;
+                       }
+               }
        }
 
        rb_link_node(node, parent, p);
@@ -79,110 +102,143 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
 /*
  * searches the tree for the given offset.
  *
- * fuzzy == 1: this is used for allocations where we are given a hint of where
- * to look for free space.  Because the hint may not be completely on an offset
- * mark, or the hint may no longer point to free space we need to fudge our
- * results a bit.  So we look for free space starting at or after offset with at
- * least bytes size.  We prefer to find as close to the given offset as we can.
- * Also if the offset is within a free space range, then we will return the free
- * space that contains the given offset, which means we can return a free space
- * chunk with an offset before the provided offset.
- *
- * fuzzy == 0: this is just a normal tree search.  Give us the free space that
- * starts at the given offset which is at least bytes size, and if its not there
- * return NULL.
+ * fuzzy - If this is set, then we are trying to make an allocation, and we just
+ * want a section that has at least bytes size and comes at or after the given
+ * offset.
  */
-static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
-                                                  u64 offset, u64 bytes,
-                                                  int fuzzy)
+static struct btrfs_free_space *
+tree_search_offset(struct btrfs_block_group_cache *block_group,
+                  u64 offset, int bitmap_only, int fuzzy)
 {
-       struct rb_node *n = root->rb_node;
-       struct btrfs_free_space *entry, *ret = NULL;
+       struct rb_node *n = block_group->free_space_offset.rb_node;
+       struct btrfs_free_space *entry, *prev = NULL;
+
+       /* find entry that is closest to the 'offset' */
+       while (1) {
+               if (!n) {
+                       entry = NULL;
+                       break;
+               }
 
-       while (n) {
                entry = rb_entry(n, struct btrfs_free_space, offset_index);
+               prev = entry;
 
-               if (offset < entry->offset) {
-                       if (fuzzy &&
-                           (!ret || entry->offset < ret->offset) &&
-                           (bytes <= entry->bytes))
-                               ret = entry;
+               if (offset < entry->offset)
                        n = n->rb_left;
-               } else if (offset > entry->offset) {
-                       if (fuzzy &&
-                           (entry->offset + entry->bytes - 1) >= offset &&
-                           bytes <= entry->bytes) {
-                               ret = entry;
-                               break;
-                       }
+               else if (offset > entry->offset)
                        n = n->rb_right;
-               } else {
-                       if (bytes > entry->bytes) {
-                               n = n->rb_right;
-                               continue;
-                       }
-                       ret = entry;
+               else
                        break;
-               }
        }
 
-       return ret;
-}
-
-/*
- * return a chunk at least bytes size, as close to offset that we can get.
- */
-static struct btrfs_free_space *tree_search_bytes(struct rb_root *root,
-                                                 u64 offset, u64 bytes)
-{
-       struct rb_node *n = root->rb_node;
-       struct btrfs_free_space *entry, *ret = NULL;
+       if (bitmap_only) {
+               if (!entry)
+                       return NULL;
+               if (entry->bitmap)
+                       return entry;
 
-       while (n) {
-               entry = rb_entry(n, struct btrfs_free_space, bytes_index);
+               /*
+                * bitmap entry and extent entry may share same offset,
+                * in that case, bitmap entry comes after extent entry.
+                */
+               n = rb_next(n);
+               if (!n)
+                       return NULL;
+               entry = rb_entry(n, struct btrfs_free_space, offset_index);
+               if (entry->offset != offset)
+                       return NULL;
 
-               if (bytes < entry->bytes) {
+               WARN_ON(!entry->bitmap);
+               return entry;
+       } else if (entry) {
+               if (entry->bitmap) {
                        /*
-                        * We prefer to get a hole size as close to the size we
-                        * are asking for so we don't take small slivers out of
-                        * huge holes, but we also want to get as close to the
-                        * offset as possible so we don't have a whole lot of
-                        * fragmentation.
+                        * if previous extent entry covers the offset,
+                        * we should return it instead of the bitmap entry
                         */
-                       if (offset <= entry->offset) {
-                               if (!ret)
-                                       ret = entry;
-                               else if (entry->bytes < ret->bytes)
-                                       ret = entry;
-                               else if (entry->offset < ret->offset)
-                                       ret = entry;
+                       n = &entry->offset_index;
+                       while (1) {
+                               n = rb_prev(n);
+                               if (!n)
+                                       break;
+                               prev = rb_entry(n, struct btrfs_free_space,
+                                               offset_index);
+                               if (!prev->bitmap) {
+                                       if (prev->offset + prev->bytes > offset)
+                                               entry = prev;
+                                       break;
+                               }
                        }
-                       n = n->rb_left;
-               } else if (bytes > entry->bytes) {
-                       n = n->rb_right;
+               }
+               return entry;
+       }
+
+       if (!prev)
+               return NULL;
+
+       /* find last entry before the 'offset' */
+       entry = prev;
+       if (entry->offset > offset) {
+               n = rb_prev(&entry->offset_index);
+               if (n) {
+                       entry = rb_entry(n, struct btrfs_free_space,
+                                       offset_index);
+                       BUG_ON(entry->offset > offset);
                } else {
-                       /*
-                        * Ok we may have multiple chunks of the wanted size,
-                        * so we don't want to take the first one we find, we
-                        * want to take the one closest to our given offset, so
-                        * keep searching just in case theres a better match.
-                        */
-                       n = n->rb_right;
-                       if (offset > entry->offset)
-                               continue;
-                       else if (!ret || entry->offset < ret->offset)
-                               ret = entry;
+                       if (fuzzy)
+                               return entry;
+                       else
+                               return NULL;
                }
        }
 
-       return ret;
+       if (entry->bitmap) {
+               n = &entry->offset_index;
+               while (1) {
+                       n = rb_prev(n);
+                       if (!n)
+                               break;
+                       prev = rb_entry(n, struct btrfs_free_space,
+                                       offset_index);
+                       if (!prev->bitmap) {
+                               if (prev->offset + prev->bytes > offset)
+                                       return prev;
+                               break;
+                       }
+               }
+               if (entry->offset + BITS_PER_BITMAP *
+                   block_group->sectorsize > offset)
+                       return entry;
+       } else if (entry->offset + entry->bytes > offset)
+               return entry;
+
+       if (!fuzzy)
+               return NULL;
+
+       while (1) {
+               if (entry->bitmap) {
+                       if (entry->offset + BITS_PER_BITMAP *
+                           block_group->sectorsize > offset)
+                               break;
+               } else {
+                       if (entry->offset + entry->bytes > offset)
+                               break;
+               }
+
+               n = rb_next(&entry->offset_index);
+               if (!n)
+                       return NULL;
+               entry = rb_entry(n, struct btrfs_free_space, offset_index);
+       }
+       return entry;
 }
 
 static void unlink_free_space(struct btrfs_block_group_cache *block_group,
                              struct btrfs_free_space *info)
 {
        rb_erase(&info->offset_index, &block_group->free_space_offset);
-       rb_erase(&info->bytes_index, &block_group->free_space_bytes);
+       block_group->free_extents--;
+       block_group->free_space -= info->bytes;
 }
 
 static int link_free_space(struct btrfs_block_group_cache *block_group,
@@ -190,17 +246,314 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
 {
        int ret = 0;
 
-
-       BUG_ON(!info->bytes);
+       BUG_ON(!info->bitmap && !info->bytes);
        ret = tree_insert_offset(&block_group->free_space_offset, info->offset,
-                                &info->offset_index);
+                                &info->offset_index, (info->bitmap != NULL));
        if (ret)
                return ret;
 
-       ret = tree_insert_bytes(&block_group->free_space_bytes, info->bytes,
-                               &info->bytes_index);
-       if (ret)
-               return ret;
+       block_group->free_space += info->bytes;
+       block_group->free_extents++;
+       return ret;
+}
+
+static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
+{
+       u64 max_bytes, possible_bytes;
+
+       /*
+        * The goal is to keep the total amount of memory used per 1gb of space
+        * at or below 32k, so we need to adjust how much memory we allow to be
+        * used by extent based free space tracking
+        */
+       max_bytes = MAX_CACHE_BYTES_PER_GIG *
+               (div64_u64(block_group->key.offset, 1024 * 1024 * 1024));
+
+       possible_bytes = (block_group->total_bitmaps * PAGE_CACHE_SIZE) +
+               (sizeof(struct btrfs_free_space) *
+                block_group->extents_thresh);
+
+       if (possible_bytes > max_bytes) {
+               int extent_bytes = max_bytes -
+                       (block_group->total_bitmaps * PAGE_CACHE_SIZE);
+
+               if (extent_bytes <= 0) {
+                       block_group->extents_thresh = 0;
+                       return;
+               }
+
+               block_group->extents_thresh = extent_bytes /
+                       (sizeof(struct btrfs_free_space));
+       }
+}
+
+static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group,
+                             struct btrfs_free_space *info, u64 offset,
+                             u64 bytes)
+{
+       unsigned long start, end;
+       unsigned long i;
+
+       start = offset_to_bit(info->offset, block_group->sectorsize, offset);
+       end = start + bytes_to_bits(bytes, block_group->sectorsize);
+       BUG_ON(end > BITS_PER_BITMAP);
+
+       for (i = start; i < end; i++)
+               clear_bit(i, info->bitmap);
+
+       info->bytes -= bytes;
+       block_group->free_space -= bytes;
+}
+
+static void bitmap_set_bits(struct btrfs_block_group_cache *block_group,
+                           struct btrfs_free_space *info, u64 offset,
+                           u64 bytes)
+{
+       unsigned long start, end;
+       unsigned long i;
+
+       start = offset_to_bit(info->offset, block_group->sectorsize, offset);
+       end = start + bytes_to_bits(bytes, block_group->sectorsize);
+       BUG_ON(end > BITS_PER_BITMAP);
+
+       for (i = start; i < end; i++)
+               set_bit(i, info->bitmap);
+
+       info->bytes += bytes;
+       block_group->free_space += bytes;
+}
+
+static int search_bitmap(struct btrfs_block_group_cache *block_group,
+                        struct btrfs_free_space *bitmap_info, u64 *offset,
+                        u64 *bytes)
+{
+       unsigned long found_bits = 0;
+       unsigned long bits, i;
+       unsigned long next_zero;
+
+       i = offset_to_bit(bitmap_info->offset, block_group->sectorsize,
+                         max_t(u64, *offset, bitmap_info->offset));
+       bits = bytes_to_bits(*bytes, block_group->sectorsize);
+
+       for (i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i);
+            i < BITS_PER_BITMAP;
+            i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i + 1)) {
+               next_zero = find_next_zero_bit(bitmap_info->bitmap,
+                                              BITS_PER_BITMAP, i);
+               if ((next_zero - i) >= bits) {
+                       found_bits = next_zero - i;
+                       break;
+               }
+               i = next_zero;
+       }
+
+       if (found_bits) {
+               *offset = (u64)(i * block_group->sectorsize) +
+                       bitmap_info->offset;
+               *bytes = (u64)(found_bits) * block_group->sectorsize;
+               return 0;
+       }
+
+       return -1;
+}
+
+static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache
+                                               *block_group, u64 *offset,
+                                               u64 *bytes, int debug)
+{
+       struct btrfs_free_space *entry;
+       struct rb_node *node;
+       int ret;
+
+       if (!block_group->free_space_offset.rb_node)
+               return NULL;
+
+       entry = tree_search_offset(block_group,
+                                  offset_to_bitmap(block_group, *offset),
+                                  0, 1);
+       if (!entry)
+               return NULL;
+
+       for (node = &entry->offset_index; node; node = rb_next(node)) {
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+               if (entry->bytes < *bytes)
+                       continue;
+
+               if (entry->bitmap) {
+                       ret = search_bitmap(block_group, entry, offset, bytes);
+                       if (!ret)
+                               return entry;
+                       continue;
+               }
+
+               *offset = entry->offset;
+               *bytes = entry->bytes;
+               return entry;
+       }
+
+       return NULL;
+}
+
+static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
+                          struct btrfs_free_space *info, u64 offset)
+{
+       u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize;
+       int max_bitmaps = (int)div64_u64(block_group->key.offset +
+                                        bytes_per_bg - 1, bytes_per_bg);
+       BUG_ON(block_group->total_bitmaps >= max_bitmaps);
+
+       info->offset = offset_to_bitmap(block_group, offset);
+       link_free_space(block_group, info);
+       block_group->total_bitmaps++;
+
+       recalculate_thresholds(block_group);
+}
+
+static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,
+                             struct btrfs_free_space *bitmap_info,
+                             u64 *offset, u64 *bytes)
+{
+       u64 end;
+
+again:
+       end = bitmap_info->offset +
+               (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1;
+
+       if (*offset > bitmap_info->offset && *offset + *bytes > end) {
+               bitmap_clear_bits(block_group, bitmap_info, *offset,
+                                 end - *offset + 1);
+               *bytes -= end - *offset + 1;
+               *offset = end + 1;
+       } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
+               bitmap_clear_bits(block_group, bitmap_info, *offset, *bytes);
+               *bytes = 0;
+       }
+
+       if (*bytes) {
+               if (!bitmap_info->bytes) {
+                       unlink_free_space(block_group, bitmap_info);
+                       kfree(bitmap_info->bitmap);
+                       kfree(bitmap_info);
+                       block_group->total_bitmaps--;
+                       recalculate_thresholds(block_group);
+               }
+
+               bitmap_info = tree_search_offset(block_group,
+                                                offset_to_bitmap(block_group,
+                                                                 *offset),
+                                                1, 0);
+               if (!bitmap_info)
+                       return -EINVAL;
+
+               if (!bitmap_info->bitmap)
+                       return -EAGAIN;
+
+               goto again;
+       } else if (!bitmap_info->bytes) {
+               unlink_free_space(block_group, bitmap_info);
+               kfree(bitmap_info->bitmap);
+               kfree(bitmap_info);
+               block_group->total_bitmaps--;
+               recalculate_thresholds(block_group);
+       }
+
+       return 0;
+}
+
+static int insert_into_bitmap(struct btrfs_block_group_cache *block_group,
+                             struct btrfs_free_space *info)
+{
+       struct btrfs_free_space *bitmap_info;
+       int added = 0;
+       u64 bytes, offset, end;
+       int ret;
+
+       /*
+        * If we are below the extents threshold then we can add this as an
+        * extent, and don't have to deal with the bitmap
+        */
+       if (block_group->free_extents < block_group->extents_thresh &&
+           info->bytes > block_group->sectorsize * 4)
+               return 0;
+
+       /*
+        * some block groups are so tiny they can't be enveloped by a bitmap, so
+        * don't even bother to create a bitmap for this
+        */
+       if (BITS_PER_BITMAP * block_group->sectorsize >
+           block_group->key.offset)
+               return 0;
+
+       bytes = info->bytes;
+       offset = info->offset;
+
+again:
+       bitmap_info = tree_search_offset(block_group,
+                                        offset_to_bitmap(block_group, offset),
+                                        1, 0);
+       if (!bitmap_info) {
+               BUG_ON(added);
+               goto new_bitmap;
+       }
+
+       end = bitmap_info->offset +
+               (u64)(BITS_PER_BITMAP * block_group->sectorsize);
+
+       if (offset >= bitmap_info->offset && offset + bytes > end) {
+               bitmap_set_bits(block_group, bitmap_info, offset,
+                               end - offset);
+               bytes -= end - offset;
+               offset = end;
+               added = 0;
+       } else if (offset >= bitmap_info->offset && offset + bytes <= end) {
+               bitmap_set_bits(block_group, bitmap_info, offset, bytes);
+               bytes = 0;
+       } else {
+               BUG();
+       }
+
+       if (!bytes) {
+               ret = 1;
+               goto out;
+       } else
+               goto again;
+
+new_bitmap:
+       if (info && info->bitmap) {
+               add_new_bitmap(block_group, info, offset);
+               added = 1;
+               info = NULL;
+               goto again;
+       } else {
+               spin_unlock(&block_group->tree_lock);
+
+               /* no pre-allocated info, allocate a new one */
+               if (!info) {
+                       info = kzalloc(sizeof(struct btrfs_free_space),
+                                      GFP_NOFS);
+                       if (!info) {
+                               spin_lock(&block_group->tree_lock);
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+               }
+
+               /* allocate the bitmap */
+               info->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
+               spin_lock(&block_group->tree_lock);
+               if (!info->bitmap) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               goto again;
+       }
+
+out:
+       if (info) {
+               if (info->bitmap)
+                       kfree(info->bitmap);
+               kfree(info);
+       }
 
        return ret;
 }
@@ -208,8 +561,8 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
 int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
                         u64 offset, u64 bytes)
 {
-       struct btrfs_free_space *right_info;
-       struct btrfs_free_space *left_info;
+       struct btrfs_free_space *right_info = NULL;
+       struct btrfs_free_space *left_info = NULL;
        struct btrfs_free_space *info = NULL;
        int ret = 0;
 
@@ -227,18 +580,38 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
         * are adding, if there is remove that struct and add a new one to
         * cover the entire range
         */
-       right_info = tree_search_offset(&block_group->free_space_offset,
-                                       offset+bytes, 0, 0);
-       left_info = tree_search_offset(&block_group->free_space_offset,
-                                      offset-1, 0, 1);
+       right_info = tree_search_offset(block_group, offset + bytes, 0, 0);
+       if (right_info && rb_prev(&right_info->offset_index))
+               left_info = rb_entry(rb_prev(&right_info->offset_index),
+                                    struct btrfs_free_space, offset_index);
+       else
+               left_info = tree_search_offset(block_group, offset - 1, 0, 0);
 
-       if (right_info) {
+       /*
+        * If there was no extent directly to the left or right of this new
+        * extent then we know we're going to have to allocate a new extent, so
+        * before we do that see if we need to drop this into a bitmap
+        */
+       if ((!left_info || left_info->bitmap) &&
+           (!right_info || right_info->bitmap)) {
+               ret = insert_into_bitmap(block_group, info);
+
+               if (ret < 0) {
+                       goto out;
+               } else if (ret) {
+                       ret = 0;
+                       goto out;
+               }
+       }
+
+       if (right_info && !right_info->bitmap) {
                unlink_free_space(block_group, right_info);
                info->bytes += right_info->bytes;
                kfree(right_info);
        }
 
-       if (left_info && left_info->offset + left_info->bytes == offset) {
+       if (left_info && !left_info->bitmap &&
+           left_info->offset + left_info->bytes == offset) {
                unlink_free_space(block_group, left_info);
                info->offset = left_info->offset;
                info->bytes += left_info->bytes;
@@ -248,11 +621,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
        ret = link_free_space(block_group, info);
        if (ret)
                kfree(info);
-
+out:
        spin_unlock(&block_group->tree_lock);
 
        if (ret) {
-               printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret);
+               printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret);
                BUG_ON(ret == -EEXIST);
        }
 
@@ -263,40 +636,65 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                            u64 offset, u64 bytes)
 {
        struct btrfs_free_space *info;
+       struct btrfs_free_space *next_info = NULL;
        int ret = 0;
 
        spin_lock(&block_group->tree_lock);
 
-       info = tree_search_offset(&block_group->free_space_offset, offset, 0,
-                                 1);
-       if (info && info->offset == offset) {
-               if (info->bytes < bytes) {
-                       printk(KERN_ERR "Found free space at %llu, size %llu,"
-                              "trying to use %llu\n",
-                              (unsigned long long)info->offset,
-                              (unsigned long long)info->bytes,
-                              (unsigned long long)bytes);
+again:
+       info = tree_search_offset(block_group, offset, 0, 0);
+       if (!info) {
+               WARN_ON(1);
+               goto out_lock;
+       }
+
+       if (info->bytes < bytes && rb_next(&info->offset_index)) {
+               u64 end;
+               next_info = rb_entry(rb_next(&info->offset_index),
+                                            struct btrfs_free_space,
+                                            offset_index);
+
+               if (next_info->bitmap)
+                       end = next_info->offset + BITS_PER_BITMAP *
+                               block_group->sectorsize - 1;
+               else
+                       end = next_info->offset + next_info->bytes;
+
+               if (next_info->bytes < bytes ||
+                   next_info->offset > offset || offset > end) {
+                       printk(KERN_CRIT "Found free space at %llu, size %llu,"
+                             " trying to use %llu\n",
+                             (unsigned long long)info->offset,
+                             (unsigned long long)info->bytes,
+                             (unsigned long long)bytes);
                        WARN_ON(1);
                        ret = -EINVAL;
-                       spin_unlock(&block_group->tree_lock);
-                       goto out;
+                       goto out_lock;
                }
-               unlink_free_space(block_group, info);
 
-               if (info->bytes == bytes) {
-                       kfree(info);
-                       spin_unlock(&block_group->tree_lock);
-                       goto out;
+               info = next_info;
+       }
+
+       if (info->bytes == bytes) {
+               unlink_free_space(block_group, info);
+               if (info->bitmap) {
+                       kfree(info->bitmap);
+                       block_group->total_bitmaps--;
                }
+               kfree(info);
+               goto out_lock;
+       }
 
+       if (!info->bitmap && info->offset == offset) {
+               unlink_free_space(block_group, info);
                info->offset += bytes;
                info->bytes -= bytes;
+               link_free_space(block_group, info);
+               goto out_lock;
+       }
 
-               ret = link_free_space(block_group, info);
-               spin_unlock(&block_group->tree_lock);
-               BUG_ON(ret);
-       } else if (info && info->offset < offset &&
-                  info->offset + info->bytes >= offset + bytes) {
+       if (!info->bitmap && info->offset <= offset &&
+           info->offset + info->bytes >= offset + bytes) {
                u64 old_start = info->offset;
                /*
                 * we're freeing space in the middle of the info,
@@ -312,7 +710,9 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                        info->offset = offset + bytes;
                        info->bytes = old_end - info->offset;
                        ret = link_free_space(block_group, info);
-                       BUG_ON(ret);
+                       WARN_ON(ret);
+                       if (ret)
+                               goto out_lock;
                } else {
                        /* the hole we're creating ends at the end
                         * of the info struct, just free the info
@@ -320,32 +720,22 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                        kfree(info);
                }
                spin_unlock(&block_group->tree_lock);
-               /* step two, insert a new info struct to cover anything
-                * before the hole
+
+               /* step two, insert a new info struct to cover
+                * anything before the hole
                 */
                ret = btrfs_add_free_space(block_group, old_start,
                                           offset - old_start);
-               BUG_ON(ret);
-       } else {
-               spin_unlock(&block_group->tree_lock);
-               if (!info) {
-                       printk(KERN_ERR "couldn't find space %llu to free\n",
-                              (unsigned long long)offset);
-                       printk(KERN_ERR "cached is %d, offset %llu bytes %llu\n",
-                              block_group->cached,
-                              (unsigned long long)block_group->key.objectid,
-                              (unsigned long long)block_group->key.offset);
-                       btrfs_dump_free_space(block_group, bytes);
-               } else if (info) {
-                       printk(KERN_ERR "hmm, found offset=%llu bytes=%llu, "
-                              "but wanted offset=%llu bytes=%llu\n",
-                              (unsigned long long)info->offset,
-                              (unsigned long long)info->bytes,
-                              (unsigned long long)offset,
-                              (unsigned long long)bytes);
-               }
-               WARN_ON(1);
+               WARN_ON(ret);
+               goto out;
        }
+
+       ret = remove_from_bitmap(block_group, info, &offset, &bytes);
+       if (ret == -EAGAIN)
+               goto again;
+       BUG_ON(ret);
+out_lock:
+       spin_unlock(&block_group->tree_lock);
 out:
        return ret;
 }
@@ -361,10 +751,13 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                if (info->bytes >= bytes)
                        count++;
-               printk(KERN_ERR "entry offset %llu, bytes %llu\n",
+               printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n",
                       (unsigned long long)info->offset,
-                      (unsigned long long)info->bytes);
+                      (unsigned long long)info->bytes,
+                      (info->bitmap) ? "yes" : "no");
        }
+       printk(KERN_INFO "block group has cluster?: %s\n",
+              list_empty(&block_group->cluster_list) ? "no" : "yes");
        printk(KERN_INFO "%d blocks of free space at or bigger than bytes is"
               "\n", count);
 }
@@ -397,26 +790,35 @@ __btrfs_return_cluster_to_free_space(
 {
        struct btrfs_free_space *entry;
        struct rb_node *node;
+       bool bitmap;
 
        spin_lock(&cluster->lock);
        if (cluster->block_group != block_group)
                goto out;
 
+       bitmap = cluster->points_to_bitmap;
+       cluster->block_group = NULL;
        cluster->window_start = 0;
+       list_del_init(&cluster->block_group_list);
+       cluster->points_to_bitmap = false;
+
+       if (bitmap)
+               goto out;
+
        node = rb_first(&cluster->root);
-       while(node) {
+       while (node) {
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
                node = rb_next(&entry->offset_index);
                rb_erase(&entry->offset_index, &cluster->root);
-               link_free_space(block_group, entry);
+               BUG_ON(entry->bitmap);
+               tree_insert_offset(&block_group->free_space_offset,
+                                  entry->offset, &entry->offset_index, 0);
        }
-       list_del_init(&cluster->block_group_list);
-
-       btrfs_put_block_group(cluster->block_group);
-       cluster->block_group = NULL;
        cluster->root.rb_node = NULL;
+
 out:
        spin_unlock(&cluster->lock);
+       btrfs_put_block_group(block_group);
        return 0;
 }
 
@@ -425,20 +827,28 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
        struct btrfs_free_space *info;
        struct rb_node *node;
        struct btrfs_free_cluster *cluster;
-       struct btrfs_free_cluster *safe;
+       struct list_head *head;
 
        spin_lock(&block_group->tree_lock);
-
-       list_for_each_entry_safe(cluster, safe, &block_group->cluster_list,
-                                block_group_list) {
+       while ((head = block_group->cluster_list.next) !=
+              &block_group->cluster_list) {
+               cluster = list_entry(head, struct btrfs_free_cluster,
+                                    block_group_list);
 
                WARN_ON(cluster->block_group != block_group);
                __btrfs_return_cluster_to_free_space(block_group, cluster);
+               if (need_resched()) {
+                       spin_unlock(&block_group->tree_lock);
+                       cond_resched();
+                       spin_lock(&block_group->tree_lock);
+               }
        }
 
-       while ((node = rb_last(&block_group->free_space_bytes)) != NULL) {
-               info = rb_entry(node, struct btrfs_free_space, bytes_index);
+       while ((node = rb_last(&block_group->free_space_offset)) != NULL) {
+               info = rb_entry(node, struct btrfs_free_space, offset_index);
                unlink_free_space(block_group, info);
+               if (info->bitmap)
+                       kfree(info->bitmap);
                kfree(info);
                if (need_resched()) {
                        spin_unlock(&block_group->tree_lock);
@@ -446,6 +856,7 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
                        spin_lock(&block_group->tree_lock);
                }
        }
+
        spin_unlock(&block_group->tree_lock);
 }
 
@@ -453,25 +864,35 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
                               u64 offset, u64 bytes, u64 empty_size)
 {
        struct btrfs_free_space *entry = NULL;
+       u64 bytes_search = bytes + empty_size;
        u64 ret = 0;
 
        spin_lock(&block_group->tree_lock);
-       entry = tree_search_offset(&block_group->free_space_offset, offset,
-                                  bytes + empty_size, 1);
+       entry = find_free_space(block_group, &offset, &bytes_search, 0);
        if (!entry)
-               entry = tree_search_bytes(&block_group->free_space_bytes,
-                                         offset, bytes + empty_size);
-       if (entry) {
+               goto out;
+
+       ret = offset;
+       if (entry->bitmap) {
+               bitmap_clear_bits(block_group, entry, offset, bytes);
+               if (!entry->bytes) {
+                       unlink_free_space(block_group, entry);
+                       kfree(entry->bitmap);
+                       kfree(entry);
+                       block_group->total_bitmaps--;
+                       recalculate_thresholds(block_group);
+               }
+       } else {
                unlink_free_space(block_group, entry);
-               ret = entry->offset;
                entry->offset += bytes;
                entry->bytes -= bytes;
-
                if (!entry->bytes)
                        kfree(entry);
                else
                        link_free_space(block_group, entry);
        }
+
+out:
        spin_unlock(&block_group->tree_lock);
 
        return ret;
@@ -517,6 +938,47 @@ int btrfs_return_cluster_to_free_space(
        return ret;
 }
 
+static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
+                                  struct btrfs_free_cluster *cluster,
+                                  u64 bytes, u64 min_start)
+{
+       struct btrfs_free_space *entry;
+       int err;
+       u64 search_start = cluster->window_start;
+       u64 search_bytes = bytes;
+       u64 ret = 0;
+
+       spin_lock(&block_group->tree_lock);
+       spin_lock(&cluster->lock);
+
+       if (!cluster->points_to_bitmap)
+               goto out;
+
+       if (cluster->block_group != block_group)
+               goto out;
+
+       entry = tree_search_offset(block_group, search_start, 0, 0);
+
+       if (!entry || !entry->bitmap)
+               goto out;
+
+       search_start = min_start;
+       search_bytes = bytes;
+
+       err = search_bitmap(block_group, entry, &search_start,
+                           &search_bytes);
+       if (err)
+               goto out;
+
+       ret = search_start;
+       bitmap_clear_bits(block_group, entry, ret, bytes);
+out:
+       spin_unlock(&cluster->lock);
+       spin_unlock(&block_group->tree_lock);
+
+       return ret;
+}
+
 /*
  * given a cluster, try to allocate 'bytes' from it, returns 0
  * if it couldn't find anything suitably large, or a logical disk offset
@@ -530,6 +992,10 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
        struct rb_node *node;
        u64 ret = 0;
 
+       if (cluster->points_to_bitmap)
+               return btrfs_alloc_from_bitmap(block_group, cluster, bytes,
+                                              min_start);
+
        spin_lock(&cluster->lock);
        if (bytes > cluster->max_size)
                goto out;
@@ -567,9 +1033,73 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
        }
 out:
        spin_unlock(&cluster->lock);
+
        return ret;
 }
 
+static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
+                               struct btrfs_free_space *entry,
+                               struct btrfs_free_cluster *cluster,
+                               u64 offset, u64 bytes, u64 min_bytes)
+{
+       unsigned long next_zero;
+       unsigned long i;
+       unsigned long search_bits;
+       unsigned long total_bits;
+       unsigned long found_bits;
+       unsigned long start = 0;
+       unsigned long total_found = 0;
+       bool found = false;
+
+       i = offset_to_bit(entry->offset, block_group->sectorsize,
+                         max_t(u64, offset, entry->offset));
+       search_bits = bytes_to_bits(min_bytes, block_group->sectorsize);
+       total_bits = bytes_to_bits(bytes, block_group->sectorsize);
+
+again:
+       found_bits = 0;
+       for (i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i);
+            i < BITS_PER_BITMAP;
+            i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) {
+               next_zero = find_next_zero_bit(entry->bitmap,
+                                              BITS_PER_BITMAP, i);
+               if (next_zero - i >= search_bits) {
+                       found_bits = next_zero - i;
+                       break;
+               }
+               i = next_zero;
+       }
+
+       if (!found_bits)
+               return -1;
+
+       if (!found) {
+               start = i;
+               found = true;
+       }
+
+       total_found += found_bits;
+
+       if (cluster->max_size < found_bits * block_group->sectorsize)
+               cluster->max_size = found_bits * block_group->sectorsize;
+
+       if (total_found < total_bits) {
+               i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, next_zero);
+               if (i - start > total_bits * 2) {
+                       total_found = 0;
+                       cluster->max_size = 0;
+                       found = false;
+               }
+               goto again;
+       }
+
+       cluster->window_start = start * block_group->sectorsize +
+               entry->offset;
+       cluster->points_to_bitmap = true;
+
+       return 0;
+}
+
 /*
  * here we try to find a cluster of blocks in a block group.  The goal
  * is to find at least bytes free and up to empty_size + bytes free.
@@ -587,12 +1117,12 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
        struct btrfs_free_space *entry = NULL;
        struct rb_node *node;
        struct btrfs_free_space *next;
-       struct btrfs_free_space *last;
+       struct btrfs_free_space *last = NULL;
        u64 min_bytes;
        u64 window_start;
        u64 window_free;
        u64 max_extent = 0;
-       int total_retries = 0;
+       bool found_bitmap = false;
        int ret;
 
        /* for metadata, allow allocates with more holes */
@@ -620,30 +1150,79 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                goto out;
        }
 again:
-       min_bytes = min(min_bytes, bytes + empty_size);
-       entry = tree_search_bytes(&block_group->free_space_bytes,
-                                 offset, min_bytes);
+       entry = tree_search_offset(block_group, offset, found_bitmap, 1);
        if (!entry) {
                ret = -ENOSPC;
                goto out;
        }
+
+       /*
+        * If found_bitmap is true, we exhausted our search for extent entries,
+        * and we just want to search all of the bitmaps that we can find, and
+        * ignore any extent entries we find.
+        */
+       while (entry->bitmap || found_bitmap ||
+              (!entry->bitmap && entry->bytes < min_bytes)) {
+               struct rb_node *node = rb_next(&entry->offset_index);
+
+               if (entry->bitmap && entry->bytes > bytes + empty_size) {
+                       ret = btrfs_bitmap_cluster(block_group, entry, cluster,
+                                                  offset, bytes + empty_size,
+                                                  min_bytes);
+                       if (!ret)
+                               goto got_it;
+               }
+
+               if (!node) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+       }
+
+       /*
+        * We already searched all the extent entries from the passed in offset
+        * to the end and didn't find enough space for the cluster, and we also
+        * didn't find any bitmaps that met our criteria, just go ahead and exit
+        */
+       if (found_bitmap) {
+               ret = -ENOSPC;
+               goto out;
+       }
+
+       cluster->points_to_bitmap = false;
        window_start = entry->offset;
        window_free = entry->bytes;
        last = entry;
        max_extent = entry->bytes;
 
-       while(1) {
+       while (1) {
                /* out window is just right, lets fill it */
                if (window_free >= bytes + empty_size)
                        break;
 
                node = rb_next(&last->offset_index);
                if (!node) {
+                       if (found_bitmap)
+                               goto again;
                        ret = -ENOSPC;
                        goto out;
                }
                next = rb_entry(node, struct btrfs_free_space, offset_index);
 
+               /*
+                * we found a bitmap, so if this search doesn't result in a
+                * cluster, we know to go and search again for the bitmaps and
+                * start looking for space there
+                */
+               if (next->bitmap) {
+                       if (!found_bitmap)
+                               offset = next->offset;
+                       found_bitmap = true;
+                       last = next;
+                       continue;
+               }
+
                /*
                 * we haven't filled the empty size and the window is
                 * very large.  reset and try again
@@ -655,19 +1234,6 @@ again:
                        window_free = entry->bytes;
                        last = entry;
                        max_extent = 0;
-                       total_retries++;
-                       if (total_retries % 64 == 0) {
-                               if (min_bytes >= (bytes + empty_size)) {
-                                       ret = -ENOSPC;
-                                       goto out;
-                               }
-                               /*
-                                * grow our allocation a bit, we're not having
-                                * much luck
-                                */
-                               min_bytes *= 2;
-                               goto again;
-                       }
                } else {
                        last = next;
                        window_free += next->bytes;
@@ -685,11 +1251,19 @@ again:
         * The cluster includes an rbtree, but only uses the offset index
         * of each free space cache entry.
         */
-       while(1) {
+       while (1) {
                node = rb_next(&entry->offset_index);
-               unlink_free_space(block_group, entry);
+               if (entry->bitmap && node) {
+                       entry = rb_entry(node, struct btrfs_free_space,
+                                        offset_index);
+                       continue;
+               } else if (entry->bitmap && !node) {
+                       break;
+               }
+
+               rb_erase(&entry->offset_index, &block_group->free_space_offset);
                ret = tree_insert_offset(&cluster->root, entry->offset,
-                                        &entry->offset_index);
+                                        &entry->offset_index, 0);
                BUG_ON(ret);
 
                if (!node || entry == last)
@@ -697,8 +1271,10 @@ again:
 
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
        }
-       ret = 0;
+
        cluster->max_size = max_extent;
+got_it:
+       ret = 0;
        atomic_inc(&block_group->count);
        list_add_tail(&cluster->block_group_list, &block_group->cluster_list);
        cluster->block_group = block_group;
@@ -718,6 +1294,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
        spin_lock_init(&cluster->refill_lock);
        cluster->root.rb_node = NULL;
        cluster->max_size = 0;
+       cluster->points_to_bitmap = false;
        INIT_LIST_HEAD(&cluster->block_group_list);
        cluster->block_group = NULL;
 }
index 266fb876405442841b31b7e8219fff82e339d821..890a8e79011b2cadc6adc545909289ed90707a27 100644 (file)
 #ifndef __BTRFS_FREE_SPACE_CACHE
 #define __BTRFS_FREE_SPACE_CACHE
 
+struct btrfs_free_space {
+       struct rb_node offset_index;
+       u64 offset;
+       u64 bytes;
+       unsigned long *bitmap;
+       struct list_head list;
+};
+
 int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
                         u64 bytenr, u64 size);
 int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
index 7ffa3d34ea1949ed97c77cb343bb8e32283bb12f..56fe83fa60c445d365f4339d1aa472cf875490d3 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mpage.h>
 #include <linux/swap.h>
@@ -2604,8 +2603,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        if (root->ref_cows)
                btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
        path = btrfs_alloc_path();
-       path->reada = -1;
        BUG_ON(!path);
+       path->reada = -1;
 
        /* FIXME, add redo link to tree so we don't leak on crash */
        key.objectid = inode->i_ino;
index 9f4db848db10dcb24c40ebe2529b3ff609c9cc1b..bd88f25889f7c5daf94bf0aec8645041bfb2ce60 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mount.h>
 #include <linux/mpage.h>
index 6d6523da0a30e769c56380c37c6e6aca019217bd..0d126be22b636c239d3e7585803e331d3d6c2f5b 100644 (file)
@@ -309,7 +309,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
        }
        printk(KERN_INFO "node %llu level %d total ptrs %d free spc %u\n",
               (unsigned long long)btrfs_header_bytenr(c),
-              btrfs_header_level(c), nr,
+             level, nr,
               (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr);
        for (i = 0; i < nr; i++) {
                btrfs_node_key_to_cpu(c, &key, i);
@@ -326,10 +326,10 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
                                        btrfs_level_size(root, level - 1),
                                        btrfs_node_ptr_generation(c, i));
                if (btrfs_is_leaf(next) &&
-                   btrfs_header_level(c) != 1)
+                  level != 1)
                        BUG();
                if (btrfs_header_level(next) !=
-                       btrfs_header_level(c) - 1)
+                      level - 1)
                        BUG();
                btrfs_print_tree(root, next);
                free_extent_buffer(next);
index 008397934778d457f7d90c3fbd03955fab230639..e71264d1c2c93acc3e1f418b6362c231dd61ad5f 100644 (file)
@@ -670,6 +670,8 @@ again:
                        err = ret;
                        goto out;
                }
+               if (ret > 0 && path2->slots[level] > 0)
+                       path2->slots[level]--;
 
                eb = path2->nodes[level];
                WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) !=
@@ -1609,6 +1611,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                BUG_ON(level == 0);
                path->lowest_level = level;
                ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0);
+               path->lowest_level = 0;
                if (ret < 0) {
                        btrfs_free_path(path);
                        return ret;
index 9f179d4832d5c90e6270c732628b4e1998a28013..6d6d06cb6dfce1e0bf950ca6d0175e9993f53010 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/mount.h>
 #include <linux/mpage.h>
index 2dbf1c1f56ee41b73068c54ee7c345a969b7f38e..e51d2bc532f8fa95a0febf2ab4682547f133b746 100644 (file)
@@ -40,6 +40,14 @@ static noinline void put_transaction(struct btrfs_transaction *transaction)
        }
 }
 
+static noinline void switch_commit_root(struct btrfs_root *root)
+{
+       down_write(&root->commit_root_sem);
+       free_extent_buffer(root->commit_root);
+       root->commit_root = btrfs_root_node(root);
+       up_write(&root->commit_root_sem);
+}
+
 /*
  * either allocate a new transaction or hop into the existing one
  */
@@ -444,9 +452,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
 
        btrfs_write_dirty_block_groups(trans, root);
 
-       ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-       BUG_ON(ret);
-
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
                if (old_root_bytenr == root->node->start)
@@ -457,13 +462,11 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                                        &root->root_key,
                                        &root->root_item);
                BUG_ON(ret);
-               btrfs_write_dirty_block_groups(trans, root);
 
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               ret = btrfs_write_dirty_block_groups(trans, root);
                BUG_ON(ret);
        }
-       free_extent_buffer(root->commit_root);
-       root->commit_root = btrfs_root_node(root);
+       switch_commit_root(root);
        return 0;
 }
 
@@ -495,9 +498,6 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                root = list_entry(next, struct btrfs_root, dirty_list);
 
                update_cowonly_root(trans, root);
-
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               BUG_ON(ret);
        }
        return 0;
 }
@@ -544,8 +544,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        btrfs_update_reloc_root(trans, root);
 
                        if (root->commit_root != root->node) {
-                               free_extent_buffer(root->commit_root);
-                               root->commit_root = btrfs_root_node(root);
+                               switch_commit_root(root);
                                btrfs_set_root_node(&root->root_item,
                                                    root->node);
                        }
@@ -943,9 +942,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                mutex_unlock(&root->fs_info->trans_mutex);
 
-               if (flush_on_commit || snap_pending) {
-                       if (flush_on_commit)
-                               btrfs_start_delalloc_inodes(root);
+               if (flush_on_commit) {
+                       btrfs_start_delalloc_inodes(root);
+                       ret = btrfs_wait_ordered_extents(root, 0);
+                       BUG_ON(ret);
+               } else if (snap_pending) {
                        ret = btrfs_wait_ordered_extents(root, 1);
                        BUG_ON(ret);
                }
@@ -1009,15 +1010,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_set_root_node(&root->fs_info->tree_root->root_item,
                            root->fs_info->tree_root->node);
-       free_extent_buffer(root->fs_info->tree_root->commit_root);
-       root->fs_info->tree_root->commit_root =
-                               btrfs_root_node(root->fs_info->tree_root);
+       switch_commit_root(root->fs_info->tree_root);
 
        btrfs_set_root_node(&root->fs_info->chunk_root->root_item,
                            root->fs_info->chunk_root->node);
-       free_extent_buffer(root->fs_info->chunk_root->commit_root);
-       root->fs_info->chunk_root->commit_root =
-                               btrfs_root_node(root->fs_info->chunk_root);
+       switch_commit_root(root->fs_info->chunk_root);
 
        update_super_roots(root);
 
@@ -1057,6 +1054,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        cur_trans->commit_done = 1;
 
        root->fs_info->last_trans_committed = cur_trans->transid;
+
        wake_up(&cur_trans->commit_wait);
 
        put_transaction(cur_trans);
index c13922206d1be59196a8c59c95f9a98bae12be74..d91b0de7c502d13ef51eaeaf667b61cc0230d8a8 100644 (file)
@@ -797,7 +797,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                return -ENOENT;
 
        inode = read_one_inode(root, key->objectid);
-       BUG_ON(!dir);
+       BUG_ON(!inode);
 
        ref_ptr = btrfs_item_ptr_offset(eb, slot);
        ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
index 3ab80e9cd76767a674e3005185ee99f3afa53433..5dbefd11b4af524f969c21b857067281eab0dc71 100644 (file)
@@ -721,7 +721,8 @@ error:
  */
 static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
                                         struct btrfs_device *device,
-                                        u64 num_bytes, u64 *start)
+                                        u64 num_bytes, u64 *start,
+                                        u64 *max_avail)
 {
        struct btrfs_key key;
        struct btrfs_root *root = device->dev_root;
@@ -758,9 +759,13 @@ static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
        if (ret < 0)
                goto error;
-       ret = btrfs_previous_item(root, path, 0, key.type);
-       if (ret < 0)
-               goto error;
+       if (ret > 0) {
+               ret = btrfs_previous_item(root, path, key.objectid, key.type);
+               if (ret < 0)
+                       goto error;
+               if (ret > 0)
+                       start_found = 1;
+       }
        l = path->nodes[0];
        btrfs_item_key_to_cpu(l, &key, path->slots[0]);
        while (1) {
@@ -803,6 +808,10 @@ no_more_items:
                        if (last_byte < search_start)
                                last_byte = search_start;
                        hole_size = key.offset - last_byte;
+
+                       if (hole_size > *max_avail)
+                               *max_avail = hole_size;
+
                        if (key.offset > last_byte &&
                            hole_size >= num_bytes) {
                                *start = last_byte;
@@ -1621,6 +1630,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
        device->fs_devices->total_rw_bytes += diff;
 
        device->total_bytes = new_size;
+       device->disk_total_bytes = new_size;
        btrfs_clear_space_info_full(device->dev_root->fs_info);
 
        return btrfs_update_device(trans, device);
@@ -2007,7 +2017,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
                        goto done;
                if (ret) {
                        ret = 0;
-                       goto done;
+                       break;
                }
 
                l = path->nodes[0];
@@ -2015,7 +2025,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
                btrfs_item_key_to_cpu(l, &key, path->slots[0]);
 
                if (key.objectid != device->devid)
-                       goto done;
+                       break;
 
                dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
                length = btrfs_dev_extent_length(l, dev_extent);
@@ -2171,6 +2181,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                             max_chunk_size);
 
 again:
+       max_avail = 0;
        if (!map || map->num_stripes != num_stripes) {
                kfree(map);
                map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
@@ -2219,7 +2230,8 @@ again:
 
                if (device->in_fs_metadata && avail >= min_free) {
                        ret = find_free_dev_extent(trans, device,
-                                                  min_free, &dev_offset);
+                                                  min_free, &dev_offset,
+                                                  &max_avail);
                        if (ret == 0) {
                                list_move_tail(&device->dev_alloc_list,
                                               &private_devs);
@@ -2795,26 +2807,6 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
                }
        }
 
-       for (i = 0; i > nr; i++) {
-               struct btrfs_multi_bio *multi;
-               struct btrfs_bio_stripe *stripe;
-               int ret;
-
-               length = 1;
-               ret = btrfs_map_block(map_tree, WRITE, buf[i],
-                                     &length, &multi, 0);
-               BUG_ON(ret);
-
-               stripe = multi->stripes;
-               for (j = 0; j < multi->num_stripes; j++) {
-                       if (stripe->physical >= physical &&
-                           physical < stripe->physical + length)
-                               break;
-               }
-               BUG_ON(j >= multi->num_stripes);
-               kfree(multi);
-       }
-
        *logical = buf;
        *naddrs = nr;
        *stripe_len = map->stripe_len;
index b7c9d5187a756e019bc88c2bcbf0ed3f9d5844f7..a173551e19d79da5ae6132be9eaa24522abd4580 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 
 #include <linux/kobject.h>
index 3a9b7a58a51d001464934963ba3df05de50bf96a..92888aa907492e813be7ea7f6c9567f2fdd32d93 100644 (file)
@@ -5,7 +5,11 @@ client generated ones by default (mount option "serverino" turned
 on by default if server supports it).  Add forceuid and forcegid
 mount options (so that when negotiating unix extensions specifying
 which uid mounted does not immediately force the server's reported
-uids to be overridden).  Add support for scope moutn parm.
+uids to be overridden).  Add support for scope mount parm. Improve
+hard link detection to use same inode for both.  Do not set
+read-only dos attribute on directories (for chmod) since Windows
+explorer special cases this attribute bit for directories for
+a different purpose.
 
 Version 1.58
 ------------
index 7f19fefd3d45a2790d426e68e59f80f687b4911c..42cec2a7c0cf41aa250aa01a18df4cc67a9264f9 100644 (file)
@@ -261,6 +261,8 @@ static ssize_t cifs_stats_proc_write(struct file *file,
                                        atomic_set(&tcon->num_reads, 0);
                                        atomic_set(&tcon->num_oplock_brks, 0);
                                        atomic_set(&tcon->num_opens, 0);
+                                       atomic_set(&tcon->num_posixopens, 0);
+                                       atomic_set(&tcon->num_posixmkdirs, 0);
                                        atomic_set(&tcon->num_closes, 0);
                                        atomic_set(&tcon->num_deletes, 0);
                                        atomic_set(&tcon->num_mkdirs, 0);
@@ -347,11 +349,15 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                                        atomic_read(&tcon->num_locks),
                                        atomic_read(&tcon->num_hardlinks),
                                        atomic_read(&tcon->num_symlinks));
-                               seq_printf(m, "\nOpens: %d Closes: %d"
+                               seq_printf(m, "\nOpens: %d Closes: %d "
                                              "Deletes: %d",
                                        atomic_read(&tcon->num_opens),
                                        atomic_read(&tcon->num_closes),
                                        atomic_read(&tcon->num_deletes));
+                               seq_printf(m, "\nPosix Opens: %d "
+                                             "Posix Mkdirs: %d",
+                                       atomic_read(&tcon->num_posixopens),
+                                       atomic_read(&tcon->num_posixmkdirs));
                                seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
                                        atomic_read(&tcon->num_mkdirs),
                                        atomic_read(&tcon->num_rmdirs));
index 4a4581cb2b5e3442e1cc0da0f0a7cd2f6de930bd..051caecf7d677ebb621ba825e7b23962aef957bb 100644 (file)
@@ -86,6 +86,9 @@ struct key_type cifs_spnego_key_type = {
 /* strlen of ";user=" */
 #define USER_KEY_LEN           6
 
+/* strlen of ";pid=0x" */
+#define PID_KEY_LEN            7
+
 /* get a key struct with a SPNEGO security blob, suitable for session setup */
 struct key *
 cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
@@ -103,7 +106,8 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
                   IP_KEY_LEN + INET6_ADDRSTRLEN +
                   MAX_MECH_STR_LEN +
                   UID_KEY_LEN + (sizeof(uid_t) * 2) +
-                  USER_KEY_LEN + strlen(sesInfo->userName) + 1;
+                  USER_KEY_LEN + strlen(sesInfo->userName) +
+                  PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
 
        spnego_key = ERR_PTR(-ENOMEM);
        description = kzalloc(desc_len, GFP_KERNEL);
@@ -141,6 +145,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        dp = description + strlen(description);
        sprintf(dp, ";user=%s", sesInfo->userName);
 
+       dp = description + strlen(description);
+       sprintf(dp, ";pid=0x%x", current->pid);
+
        cFYI(1, ("key description = %s", description));
        spnego_key = request_key(&cifs_spnego_key_type, description, "");
 
index 1403b5d86a739d67725e0dc94db1bec593e5ddab..6941c22398a6ac4097528add80d3ebcbcad2bbc2 100644 (file)
@@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
 
 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
-                      struct inode *inode)
+                      struct cifs_fattr *fattr)
 {
        int i;
        int num_aces = 0;
@@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        if (!pdacl) {
                /* no DACL in the security descriptor, set
                   all the permissions for user/group/other */
-               inode->i_mode |= S_IRWXUGO;
+               fattr->cf_mode |= S_IRWXUGO;
                return;
        }
 
@@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        /* reset rwx permissions for user/group/other.
           Also, if num_aces is 0 i.e. DACL has no ACEs,
           user/group/other have no permissions */
-       inode->i_mode &= ~(S_IRWXUGO);
+       fattr->cf_mode &= ~(S_IRWXUGO);
 
        acl_base = (char *)pdacl;
        acl_size = sizeof(struct cifs_acl);
@@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                        if (compare_sids(&(ppace[i]->sid), pownersid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &user_mask);
                        if (compare_sids(&(ppace[i]->sid), pgrpsid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &group_mask);
                        if (compare_sids(&(ppace[i]->sid), &sid_everyone))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &other_mask);
 
 /*                     memcpy((void *)(&(cifscred->aces[i])),
@@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 
 /* Convert CIFS ACL to POSIX form */
 static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
-                         struct inode *inode)
+                         struct cifs_fattr *fattr)
 {
        int rc;
        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
@@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        char *end_of_acl = ((char *)pntsd) + acl_len;
        __u32 dacloffset;
 
-       if ((inode == NULL) || (pntsd == NULL))
+       if (pntsd == NULL)
                return -EIO;
 
        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
@@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
 
        if (dacloffset)
                parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
-                          group_sid_ptr, inode);
+                          group_sid_ptr, fattr);
        else
                cFYI(1, ("no ACL")); /* BB grant all or default perms? */
 
@@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
                        sizeof(struct cifs_sid)); */
 
-
        return 0;
 }
 
@@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
-void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                    const char *path, const __u16 *pfid)
+void
+cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+                 struct inode *inode, const char *path, const __u16 *pfid)
 {
        struct cifs_ntsd *pntsd = NULL;
        u32 acllen = 0;
@@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
 
        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
        if (pntsd)
-               rc = parse_sec_desc(pntsd, acllen, inode);
+               rc = parse_sec_desc(pntsd, acllen, fattr);
        if (rc)
                cFYI(1, ("parse sec desc failed rc = %d", rc));
 
index 9f669f982c4d4fe74b4640b221f04d9bd183b597..44f30504b82d1bbe511da6d4def1342067359deb 100644 (file)
@@ -308,7 +308,6 @@ cifs_alloc_inode(struct super_block *sb)
        if (!cifs_inode)
                return NULL;
        cifs_inode->cifsAttrs = 0x20;   /* default */
-       atomic_set(&cifs_inode->inUse, 0);
        cifs_inode->time = 0;
        cifs_inode->write_behind_rc = 0;
        /* Until the file is open and we have gotten oplock
index 9570a0e8023f4258941d1f4cdc0e8141188a622d..6c170948300d9be5cc6d8cc47eac8d73053bf390 100644 (file)
 
 #define ROOT_I 2
 
+/*
+ * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
+ * so that it will fit.
+ */
+static inline ino_t
+cifs_uniqueid_to_ino_t(u64 fileid)
+{
+       ino_t ino = (ino_t) fileid;
+       if (sizeof(ino_t) < sizeof(u64))
+               ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
+       return ino;
+}
+
 extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
@@ -100,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.59"
+#define CIFS_VERSION   "1.60"
 #endif                         /* _CIFSFS_H */
index e1225e6ded2fc61a7fed19d2d39f879146192bb2..6084d6379c03fb95ddf268e33ba903a55aa3b7c7 100644 (file)
@@ -260,6 +260,8 @@ struct cifsTconInfo {
        atomic_t num_closes;
        atomic_t num_deletes;
        atomic_t num_mkdirs;
+       atomic_t num_posixopens;
+       atomic_t num_posixmkdirs;
        atomic_t num_rmdirs;
        atomic_t num_renames;
        atomic_t num_t2renames;
@@ -364,13 +366,13 @@ struct cifsInodeInfo {
        struct list_head openFileList;
        int write_behind_rc;
        __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
-       atomic_t inUse;  /* num concurrent users (local openers cifs) of file*/
        unsigned long time;     /* jiffies of last update/check of inode */
        bool clientCanCacheRead:1;      /* read oplock */
        bool clientCanCacheAll:1;       /* read and writebehind oplock */
        bool oplockPending:1;
        bool delete_pending:1;          /* DELETE_ON_CLOSE is set */
        u64  server_eof;                /* current file size on server */
+       u64  uniqueid;                  /* server inode number */
        struct inode vfs_inode;
 };
 
@@ -472,6 +474,32 @@ struct dfs_info3_param {
        char *node_name;
 };
 
+/*
+ * common struct for holding inode info when searching for or updating an
+ * inode with new info
+ */
+
+#define CIFS_FATTR_DFS_REFERRAL                0x1
+#define CIFS_FATTR_DELETE_PENDING      0x2
+#define CIFS_FATTR_NEED_REVAL          0x4
+
+struct cifs_fattr {
+       u32             cf_flags;
+       u32             cf_cifsattrs;
+       u64             cf_uniqueid;
+       u64             cf_eof;
+       u64             cf_bytes;
+       uid_t           cf_uid;
+       gid_t           cf_gid;
+       umode_t         cf_mode;
+       dev_t           cf_rdev;
+       unsigned int    cf_nlink;
+       unsigned int    cf_dtype;
+       struct timespec cf_atime;
+       struct timespec cf_mtime;
+       struct timespec cf_ctime;
+};
+
 static inline void free_dfs_info_param(struct dfs_info3_param *param)
 {
        if (param) {
index a785f69dbc9feecd616eba56dfaa47e8ab74b392..2d07f890a842f1fac459c39d2d53044a9c19df91 100644 (file)
@@ -2328,19 +2328,7 @@ struct file_attrib_tag {
 typedef struct {
        __le32 NextEntryOffset;
        __u32 ResumeKey; /* as with FileIndex - no need to convert */
-       __le64 EndOfFile;
-       __le64 NumOfBytes;
-       __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
-       __le64 LastAccessTime;
-       __le64 LastModificationTime;
-       __le64 Uid;
-       __le64 Gid;
-       __le32 Type;
-       __le64 DevMajor;
-       __le64 DevMinor;
-       __le64 UniqueId;
-       __le64 Permissions;
-       __le64 Nlinks;
+       FILE_UNIX_BASIC_INFO basic;
        char FileName[1];
 } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
 
index c419416a42eef09dcb38db00a3c2a8b496f7799c..da8fbf565991906320359743d0860ee0d026b812 100644 (file)
@@ -98,9 +98,13 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
 extern int cifs_posix_open(char *full_path, struct inode **pinode,
                           struct super_block *sb, int mode, int oflags,
                           int *poplock, __u16 *pnetfid, int xid);
-extern void posix_fill_in_inode(struct inode *tmp_inode,
-                               FILE_UNIX_BASIC_INFO *pData, int isNewInode);
-extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
+extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
+                                    FILE_UNIX_BASIC_INFO *info,
+                                    struct cifs_sb_info *cifs_sb);
+extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
+extern struct inode *cifs_iget(struct super_block *sb,
+                              struct cifs_fattr *fattr);
+
 extern int cifs_get_inode_info(struct inode **pinode,
                        const unsigned char *search_path,
                        FILE_ALL_INFO *pfile_info,
@@ -108,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode,
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, int xid);
-extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                           const char *path, const __u16 *pfid);
+extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
+                             struct cifs_fattr *fattr, struct inode *inode,
+                             const char *path, const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
@@ -215,7 +220,11 @@ struct cifs_unix_set_info_args {
        dev_t   device;
 };
 
-extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
+extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                                 const struct cifs_unix_set_info_args *args,
+                                 u16 fid, u32 pid_of_opener);
+
+extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon,
                        char *fileName,
                        const struct cifs_unix_set_info_args *args,
                        const struct nls_table *nls_codepage,
index 61007c6274975f0077b5aa488112dbbb4b80f6a0..1866bc2927d4f376182e98e71182fcff345f0a71 100644 (file)
@@ -1113,7 +1113,10 @@ PsxCreat:
 psx_create_err:
        cifs_buf_release(pSMB);
 
-       cifs_stats_inc(&tcon->num_mkdirs);
+       if (posix_flags & SMB_O_DIRECTORY)
+               cifs_stats_inc(&tcon->num_posixmkdirs);
+       else
+               cifs_stats_inc(&tcon->num_posixopens);
 
        if (rc == -EAGAIN)
                goto PsxCreat;
@@ -5074,10 +5077,114 @@ SetAttrLgcyRetry:
 }
 #endif /* temporarily unneeded SetAttr legacy function */
 
+static void
+cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
+                       const struct cifs_unix_set_info_args *args)
+{
+       u64 mode = args->mode;
+
+       /*
+        * Samba server ignores set of file size to zero due to bugs in some
+        * older clients, but we should be precise - we use SetFileSize to
+        * set file size and do not want to truncate file size to zero
+        * accidently as happened on one Samba server beta by putting
+        * zero instead of -1 here
+        */
+       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
+       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
+       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
+       data_offset->LastAccessTime = cpu_to_le64(args->atime);
+       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
+       data_offset->Uid = cpu_to_le64(args->uid);
+       data_offset->Gid = cpu_to_le64(args->gid);
+       /* better to leave device as zero when it is  */
+       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
+       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
+       data_offset->Permissions = cpu_to_le64(mode);
+
+       if (S_ISREG(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FILE);
+       else if (S_ISDIR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_DIR);
+       else if (S_ISLNK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+       else if (S_ISCHR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+       else if (S_ISBLK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+       else if (S_ISFIFO(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FIFO);
+       else if (S_ISSOCK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+}
+
 int
-CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
-                  const struct cifs_unix_set_info_args *args,
-                  const struct nls_table *nls_codepage, int remap)
+CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                      const struct cifs_unix_set_info_args *args,
+                      u16 fid, u32 pid_of_opener)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       FILE_UNIX_BASIC_INFO *data_offset;
+       int rc = 0;
+       u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Set Unix Info (via SetFileInfo)"));
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (FILE_UNIX_BASIC_INFO *)
+                               ((char *)(&pSMB->hdr.Protocol) + offset);
+       count = sizeof(FILE_UNIX_BASIC_INFO);
+
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = fid;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       cifs_fill_unix_set_info(data_offset, args);
+
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
+               cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
+
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
+               since file handle passed in no longer valid */
+
+       return rc;
+}
+
+int
+CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+                      const struct cifs_unix_set_info_args *args,
+                      const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5086,7 +5193,6 @@ CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
        int bytes_returned = 0;
        FILE_UNIX_BASIC_INFO *data_offset;
        __u16 params, param_offset, offset, count, byte_count;
-       __u64 mode = args->mode;
 
        cFYI(1, ("In SetUID/GID/Mode"));
 setPermsRetry:
@@ -5137,38 +5243,8 @@ setPermsRetry:
        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
-       /* Samba server ignores set of file size to zero due to bugs in some
-       older clients, but we should be precise - we use SetFileSize to
-       set file size and do not want to truncate file size to zero
-       accidently as happened on one Samba server beta by putting
-       zero instead of -1 here */
-       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
-       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
-       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
-       data_offset->LastAccessTime = cpu_to_le64(args->atime);
-       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
-       data_offset->Uid = cpu_to_le64(args->uid);
-       data_offset->Gid = cpu_to_le64(args->gid);
-       /* better to leave device as zero when it is  */
-       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
-       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
-       data_offset->Permissions = cpu_to_le64(mode);
-
-       if (S_ISREG(mode))
-               data_offset->Type = cpu_to_le32(UNIX_FILE);
-       else if (S_ISDIR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_DIR);
-       else if (S_ISLNK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
-       else if (S_ISCHR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
-       else if (S_ISBLK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
-       else if (S_ISFIFO(mode))
-               data_offset->Type = cpu_to_le32(UNIX_FIFO);
-       else if (S_ISSOCK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
 
+       cifs_fill_unix_set_info(data_offset, args);
 
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
index e16d7592116ad7dbedd557d8df37497d6370155c..fc44d316d0bb4702eaa8d083cf9ed0eb746304ca 100644 (file)
@@ -2452,10 +2452,10 @@ try_mount_again:
                tcon->local_lease = volume_info->local_lease;
        }
        if (pSesInfo) {
-               if (pSesInfo->capabilities & CAP_LARGE_FILES) {
-                       sb->s_maxbytes = (u64) 1 << 63;
-               else
-                       sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
+               if (pSesInfo->capabilities & CAP_LARGE_FILES)
+                       sb->s_maxbytes = MAX_LFS_FILESIZE;
+               else
+                       sb->s_maxbytes = MAX_NON_LFS;
        }
 
        /* BB FIXME fix time_gran to be larger for LANMAN sessions */
@@ -2726,6 +2726,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
 
                /* mostly informational -- no need to fail on error here */
+               kfree(tcon->nativeFileSystem);
                tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr,
                                                      bytes_left, is_unicode,
                                                      nls_codepage);
index 7dc6b74f9deffc31de7fe5ea122eb0945b564927..4326ffd90fa91b92086ab993bcfe7631396c7cf4 100644 (file)
@@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        FILE_UNIX_BASIC_INFO *presp_data;
        __u32 posix_flags = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       struct cifs_fattr fattr;
 
        cFYI(1, ("posix open %s", full_path));
 
@@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        if (presp_data->Type == cpu_to_le32(-1))
                goto posix_open_ret; /* open ok, caller does qpathinfo */
 
-       /* get new inode and set it up */
        if (!pinode)
                goto posix_open_ret; /* caller does not need info */
 
+       cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
+
+       /* get new inode and set it up */
        if (*pinode == NULL) {
-               __u64 unique_id = le64_to_cpu(presp_data->UniqueId);
-               *pinode = cifs_new_inode(sb, &unique_id);
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode) {
+                       rc = -ENOMEM;
+                       goto posix_open_ret;
+               }
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
        }
-       /* else an inode was passed in. Update its info, don't create one */
-
-       /* We do not need to close the file if new_inode fails since
-          the caller will retry qpathinfo as long as inode is null */
-       if (*pinode == NULL)
-               goto posix_open_ret;
-
-       posix_fill_in_inode(*pinode, presp_data, 1);
 
        cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
 
@@ -425,9 +425,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
-                       cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+                                       cifs_sb->local_nls,
+                                       cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
        } else {
                /* BB implement mode setting via Windows security
                   descriptors e.g. */
@@ -515,10 +516,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
-                       &args, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+                                           cifs_sb->local_nls,
+                                           cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
 
                if (!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -643,6 +644,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                        }
        }
 
+       /*
+        * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
+        * the VFS handle the create.
+        */
+       if (nd->flags & LOOKUP_EXCL) {
+               d_instantiate(direntry, NULL);
+               return 0;
+       }
+
        /* can not grab the rename sem here since it would
        deadlock in the cases (beginning of sys_rename itself)
        in which we already have the sb rename sem */
index 97ce4bf89d152a85df85aa5486927e85e4f5893d..c34b7f8a217b383b1f8505822f00052276779833 100644 (file)
@@ -448,9 +448,9 @@ int cifs_open(struct inode *inode, struct file *file)
                                .mtime  = NO_CHANGE_64,
                                .device = 0,
                        };
-                       CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
-                                           cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
+                       CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+                                              cifs_sb->local_nls,
+                                              cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                }
        }
index 155c9e785d0c65a29d29e8d695c192502ea89ece..82d83839655eed195fa91dd10120e048309bd287 100644 (file)
@@ -77,239 +77,202 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
        }
 }
 
-static void cifs_unix_info_to_inode(struct inode *inode,
-               FILE_UNIX_BASIC_INFO *info, int force_uid_gid)
+/* populate an inode with info from a cifs_fattr struct */
+void
+cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 {
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
-       __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes);
-       __u64 end_of_file = le64_to_cpu(info->EndOfFile);
+       unsigned long oldtime = cifs_i->time;
+
+       inode->i_atime = fattr->cf_atime;
+       inode->i_mtime = fattr->cf_mtime;
+       inode->i_ctime = fattr->cf_ctime;
+       inode->i_rdev = fattr->cf_rdev;
+       inode->i_nlink = fattr->cf_nlink;
+       inode->i_uid = fattr->cf_uid;
+       inode->i_gid = fattr->cf_gid;
+
+       /* if dynperm is set, don't clobber existing mode */
+       if (inode->i_state & I_NEW ||
+           !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
+               inode->i_mode = fattr->cf_mode;
+
+       cifs_i->cifsAttrs = fattr->cf_cifsattrs;
+       cifs_i->uniqueid = fattr->cf_uniqueid;
+
+       if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
+               cifs_i->time = 0;
+       else
+               cifs_i->time = jiffies;
+
+       cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
+                oldtime, cifs_i->time));
 
-       inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime);
-       inode->i_mtime =
-               cifs_NTtimeToUnix(info->LastModificationTime);
-       inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
-       inode->i_mode = le64_to_cpu(info->Permissions);
+       cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
+
+       /*
+        * Can't safely change the file size here if the client is writing to
+        * it due to potential races.
+        */
+       spin_lock(&inode->i_lock);
+       if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
+               i_size_write(inode, fattr->cf_eof);
+
+               /*
+                * i_blocks is not related to (i_size / i_blksize),
+                * but instead 512 byte (2**9) size is required for
+                * calculating num blocks.
+                */
+               inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
+       }
+       spin_unlock(&inode->i_lock);
+
+       cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
+}
+
+/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
+void
+cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
+                        struct cifs_sb_info *cifs_sb)
+{
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
+       fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+
+       fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
+       fattr->cf_mode = le64_to_cpu(info->Permissions);
 
        /*
         * Since we set the inode type below we need to mask off
         * to avoid strange results if bits set above.
         */
-       inode->i_mode &= ~S_IFMT;
+       fattr->cf_mode &= ~S_IFMT;
        switch (le32_to_cpu(info->Type)) {
        case UNIX_FILE:
-               inode->i_mode |= S_IFREG;
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                break;
        case UNIX_SYMLINK:
-               inode->i_mode |= S_IFLNK;
+               fattr->cf_mode |= S_IFLNK;
+               fattr->cf_dtype = DT_LNK;
                break;
        case UNIX_DIR:
-               inode->i_mode |= S_IFDIR;
+               fattr->cf_mode |= S_IFDIR;
+               fattr->cf_dtype = DT_DIR;
                break;
        case UNIX_CHARDEV:
-               inode->i_mode |= S_IFCHR;
-               inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
-                                     le64_to_cpu(info->DevMinor) & MINORMASK);
+               fattr->cf_mode |= S_IFCHR;
+               fattr->cf_dtype = DT_CHR;
+               fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
+                                      le64_to_cpu(info->DevMinor) & MINORMASK);
                break;
        case UNIX_BLOCKDEV:
-               inode->i_mode |= S_IFBLK;
-               inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor),
-                                     le64_to_cpu(info->DevMinor) & MINORMASK);
+               fattr->cf_mode |= S_IFBLK;
+               fattr->cf_dtype = DT_BLK;
+               fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
+                                      le64_to_cpu(info->DevMinor) & MINORMASK);
                break;
        case UNIX_FIFO:
-               inode->i_mode |= S_IFIFO;
+               fattr->cf_mode |= S_IFIFO;
+               fattr->cf_dtype = DT_FIFO;
                break;
        case UNIX_SOCKET:
-               inode->i_mode |= S_IFSOCK;
+               fattr->cf_mode |= S_IFSOCK;
+               fattr->cf_dtype = DT_SOCK;
                break;
        default:
                /* safest to call it a file if we do not know */
-               inode->i_mode |= S_IFREG;
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                cFYI(1, ("unknown type %d", le32_to_cpu(info->Type)));
                break;
        }
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) &&
-           !force_uid_gid)
-               inode->i_uid = cifs_sb->mnt_uid;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+               fattr->cf_uid = cifs_sb->mnt_uid;
        else
-               inode->i_uid = le64_to_cpu(info->Uid);
+               fattr->cf_uid = le64_to_cpu(info->Uid);
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) &&
-           !force_uid_gid)
-               inode->i_gid = cifs_sb->mnt_gid;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+               fattr->cf_gid = cifs_sb->mnt_gid;
        else
-               inode->i_gid = le64_to_cpu(info->Gid);
+               fattr->cf_gid = le64_to_cpu(info->Gid);
 
-       inode->i_nlink = le64_to_cpu(info->Nlinks);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /*
-                * We can not safely change the file size here if the client
-                * is writing to it due to potential races.
-                */
-               i_size_write(inode, end_of_file);
-
-               /*
-                * i_blocks is not related to (i_size / i_blksize),
-                * but instead 512 byte (2**9) size is required for
-                * calculating num blocks.
-                */
-               inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
-       }
-       spin_unlock(&inode->i_lock);
+       fattr->cf_nlink = le64_to_cpu(info->Nlinks);
 }
 
-
 /*
- *     Needed to setup inode data for the directory which is the
- *     junction to the new submount (ie to setup the fake directory
- *      which represents a DFS referral)
- */
-static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
-                              struct super_block *sb)
-{
-       struct inode *pinode = NULL;
-
-       memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO));
-
-/*     __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
-       __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
-       __u64 UniqueId = 0;  */
-       pfnd_dat->LastStatusChange =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastAccessTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastModificationTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
-       pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
-       pfnd_dat->Nlinks = cpu_to_le64(2);
-       if (sb->s_root)
-               pinode = sb->s_root->d_inode;
-       if (pinode == NULL)
-               return;
-
-       /* fill in default values for the remaining based on root
-          inode since we can not query the server for this inode info */
-       pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
-       pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
-       pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
-       pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
-}
-
-/**
- * cifs_new inode - create new inode, initialize, and hash it
- * @sb - pointer to superblock
- * @inum - if valid pointer and serverino is enabled, replace i_ino with val
- *
- * Create a new inode, initialize it for CIFS and hash it. Returns the new
- * inode or NULL if one couldn't be allocated.
+ * Fill a cifs_fattr struct with fake inode info.
  *
- * If the share isn't mounted with "serverino" or inum is a NULL pointer then
- * we'll just use the inode number assigned by new_inode(). Note that this can
- * mean i_ino collisions since the i_ino assigned by new_inode is not
- * guaranteed to be unique.
+ * Needed to setup cifs_fattr data for the directory which is the
+ * junction to the new submount (ie to setup the fake directory
+ * which represents a DFS referral).
  */
-struct inode *
-cifs_new_inode(struct super_block *sb, __u64 *inum)
+static void
+cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
 {
-       struct inode *inode;
-
-       inode = new_inode(sb);
-       if (inode == NULL)
-               return NULL;
-
-       /*
-        * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
-        *     stop passing inum as ptr. Are there sanity checks we can use to
-        *     ensure that the server is really filling in that field? Also,
-        *     if serverino is disabled, perhaps we should be using iunique()?
-        */
-       if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
-               inode->i_ino = (unsigned long) *inum;
-
-       /*
-        * must set this here instead of cifs_alloc_inode since VFS will
-        * clobber i_flags
-        */
-       if (sb->s_flags & MS_NOATIME)
-               inode->i_flags |= S_NOATIME | S_NOCMTIME;
-
-       insert_inode_hash(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-       return inode;
+       cFYI(1, ("creating fake fattr for DFS referral"));
+
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
+       fattr->cf_atime = CURRENT_TIME;
+       fattr->cf_ctime = CURRENT_TIME;
+       fattr->cf_mtime = CURRENT_TIME;
+       fattr->cf_nlink = 2;
+       fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
 int cifs_get_inode_info_unix(struct inode **pinode,
-       const unsigned char *full_path, struct super_block *sb, int xid)
+                            const unsigned char *full_path,
+                            struct super_block *sb, int xid)
 {
-       int rc = 0;
+       int rc;
        FILE_UNIX_BASIC_INFO find_data;
-       struct cifsTconInfo *pTcon;
-       struct inode *inode;
+       struct cifs_fattr fattr;
+       struct cifsTconInfo *tcon;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       bool is_dfs_referral = false;
-       struct cifsInodeInfo *cifsInfo;
-       __u64 num_of_bytes;
-       __u64 end_of_file;
 
-       pTcon = cifs_sb->tcon;
+       tcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", full_path));
 
        /* could have done a find first instead but this returns more info */
-       rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
+       rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
                                  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if (rc == -EREMOTE && !is_dfs_referral) {
-               is_dfs_referral = true;
-               cFYI(DBG2, ("DFS ref"));
-               /* for DFS, server does not give us real inode data */
-               fill_fake_finddataunix(&find_data, sb);
-               rc = 0;
-       } else if (rc)
-               goto cgiiu_exit;
 
-       num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
-       end_of_file = le64_to_cpu(find_data.EndOfFile);
+       if (!rc) {
+               cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, sb);
+               rc = 0;
+       } else {
+               return rc;
+       }
 
-       /* get new inode */
        if (*pinode == NULL) {
-               __u64 unique_id = le64_to_cpu(find_data.UniqueId);
-               *pinode = cifs_new_inode(sb, &unique_id);
-               if (*pinode == NULL) {
+               /* get new inode */
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode)
                        rc = -ENOMEM;
-                       goto cgiiu_exit;
-               }
+       } else {
+               /* we already have inode, update it */
+               cifs_fattr_to_inode(*pinode, &fattr);
        }
 
-       inode = *pinode;
-       cifsInfo = CIFS_I(inode);
-
-       cFYI(1, ("Old time %ld", cifsInfo->time));
-       cifsInfo->time = jiffies;
-       cFYI(1, ("New time %ld", cifsInfo->time));
-       /* this is ok to set on every inode revalidate */
-       atomic_set(&cifsInfo->inUse, 1);
-
-       cifs_unix_info_to_inode(inode, &find_data, 0);
-
-       if (num_of_bytes < end_of_file)
-               cFYI(1, ("allocation size less than end of file"));
-       cFYI(1, ("Size %ld and blocks %llu",
-               (unsigned long) inode->i_size,
-               (unsigned long long)inode->i_blocks));
-
-       cifs_set_ops(inode, is_dfs_referral);
-cgiiu_exit:
        return rc;
 }
 
-static int decode_sfu_inode(struct inode *inode, __u64 size,
-                           const unsigned char *path,
-                           struct cifs_sb_info *cifs_sb, int xid)
+static int
+cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
+             struct cifs_sb_info *cifs_sb, int xid)
 {
        int rc;
        int oplock = 0;
@@ -321,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
        pbuf = buf;
 
-       if (size == 0) {
-               inode->i_mode |= S_IFIFO;
+       fattr->cf_mode &= ~S_IFMT;
+
+       if (fattr->cf_eof == 0) {
+               fattr->cf_mode |= S_IFIFO;
+               fattr->cf_dtype = DT_FIFO;
                return 0;
-       } else if (size < 8) {
+       } else if (fattr->cf_eof < 8) {
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                return -EINVAL;  /* EOPNOTSUPP? */
        }
 
@@ -336,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
        if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
-               rc = CIFSSMBRead(xid, pTcon,
-                                netfid,
+               rc = CIFSSMBRead(xid, pTcon, netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
                        if (memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1, ("Block device"));
-                               inode->i_mode |= S_IFBLK;
+                               fattr->cf_mode |= S_IFBLK;
+                               fattr->cf_dtype = DT_BLK;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
                                cFYI(1, ("Char device"));
-                               inode->i_mode |= S_IFCHR;
+                               fattr->cf_mode |= S_IFCHR;
+                               fattr->cf_dtype = DT_CHR;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
                                cFYI(1, ("Symlink"));
-                               inode->i_mode |= S_IFLNK;
+                               fattr->cf_mode |= S_IFLNK;
+                               fattr->cf_dtype = DT_LNK;
                        } else {
-                               inode->i_mode |= S_IFREG; /* file? */
+                               fattr->cf_mode |= S_IFREG; /* file? */
+                               fattr->cf_dtype = DT_REG;
                                rc = -EOPNOTSUPP;
                        }
                } else {
-                       inode->i_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_dtype = DT_REG;
                        rc = -EOPNOTSUPP; /* or some unknown SFU type */
                }
                CIFSSMBClose(xid, pTcon, netfid);
@@ -381,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
 #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
 
-static int get_sfu_mode(struct inode *inode,
-                       const unsigned char *path,
-                       struct cifs_sb_info *cifs_sb, int xid)
+/*
+ * Fetch mode bits as provided by SFU.
+ *
+ * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
+ */
+static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
+                        struct cifs_sb_info *cifs_sb, int xid)
 {
 #ifdef CONFIG_CIFS_XATTR
        ssize_t rc;
@@ -391,68 +367,80 @@ static int get_sfu_mode(struct inode *inode,
        __u32 mode;
 
        rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
-                       ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+                           ea_value, 4 /* size of buf */, cifs_sb->local_nls,
+                           cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
                mode = le32_to_cpu(*((__le32 *)ea_value));
-               inode->i_mode &= ~SFBITS_MASK;
-               cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
-               inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
+               fattr->cf_mode &= ~SFBITS_MASK;
+               cFYI(1, ("special bits 0%o org mode 0%o", mode,
+                        fattr->cf_mode));
+               fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
                cFYI(1, ("special mode bits 0%o", mode));
-               return 0;
-       } else {
-               return 0;
        }
+
+       return 0;
 #else
        return -EOPNOTSUPP;
 #endif
 }
 
-/*
- *     Needed to setup inode data for the directory which is the
- *     junction to the new submount (ie to setup the fake directory
- *      which represents a DFS referral)
- */
-static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
-                              struct super_block *sb)
+/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
+static void
+cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
+                      struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
-       memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
-
-/*     __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
-       __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
-       __u8 pfnd_dat->DeletePending = 0;
-       __u8 pfnd_data->Directory = 0;
-       __le32 pfnd_dat->EASize = 0;
-       __u64 pfnd_dat->IndexNumber = 0;
-       __u64 pfnd_dat->IndexNumber1 = 0;  */
-       pfnd_dat->CreationTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastAccessTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastWriteTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->ChangeTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
-       pfnd_dat->NumberOfLinks = cpu_to_le32(2);
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
+       if (info->DeletePending)
+               fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
+
+       if (info->LastAccessTime)
+               fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       else
+               fattr->cf_atime = CURRENT_TIME;
+
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       if (adjust_tz) {
+               fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+               fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+       }
+
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
+       } else {
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
+
+               /* clear write bits if ATTR_READONLY is set */
+               if (fattr->cf_cifsattrs & ATTR_READONLY)
+                       fattr->cf_mode &= ~(S_IWUGO);
+       }
+
+       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
 int cifs_get_inode_info(struct inode **pinode,
        const unsigned char *full_path, FILE_ALL_INFO *pfindData,
        struct super_block *sb, int xid, const __u16 *pfid)
 {
-       int rc = 0;
-       __u32 attr;
-       struct cifsInodeInfo *cifsInfo;
+       int rc = 0, tmprc;
        struct cifsTconInfo *pTcon;
-       struct inode *inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *buf = NULL;
        bool adjustTZ = false;
-       bool is_dfs_referral = false;
-       umode_t default_mode;
+       struct cifs_fattr fattr;
 
        pTcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", full_path));
@@ -487,163 +475,85 @@ int cifs_get_inode_info(struct inode **pinode,
                        adjustTZ = true;
                }
        }
-       /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
-       if (rc == -EREMOTE) {
-               is_dfs_referral = true;
-               fill_fake_finddata(pfindData, sb);
+
+       if (!rc) {
+               cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
+                                      cifs_sb, adjustTZ);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, sb);
                rc = 0;
-       } else if (rc)
+       } else {
                goto cgii_exit;
+       }
 
-       attr = le32_to_cpu(pfindData->Attributes);
-
-       /* get new inode */
+       /*
+        * If an inode wasn't passed in, then get the inode number
+        *
+        * Is an i_ino of zero legal? Can we use that to check if the server
+        * supports returning inode numbers?  Are there other sanity checks we
+        * can use to ensure that the server is really filling in that field?
+        *
+        * We can not use the IndexNumber field by default from Windows or
+        * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
+        * CIFS spec claims that this value is unique within the scope of a
+        * share, and the windows docs hint that it's actually unique
+        * per-machine.
+        *
+        * There may be higher info levels that work but are there Windows
+        * server or network appliances for which IndexNumber field is not
+        * guaranteed unique?
+        */
        if (*pinode == NULL) {
-               __u64 inode_num;
-               __u64 *pinum = &inode_num;
-
-               /* Is an i_ino of zero legal? Can we use that to check
-                  if the server supports returning inode numbers?  Are
-                  there other sanity checks we can use to ensure that
-                  the server is really filling in that field? */
-
-               /* We can not use the IndexNumber field by default from
-                  Windows or Samba (in ALL_INFO buf) but we can request
-                  it explicitly.  It may not be unique presumably if
-                  the server has multiple devices mounted under one share */
-
-               /* There may be higher info levels that work but are
-                  there Windows server or network appliances for which
-                  IndexNumber field is not guaranteed unique? */
-
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                        int rc1 = 0;
 
                        rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
-                                       full_path, pinum,
+                                       full_path, &fattr.cf_uniqueid,
                                        cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (rc1) {
                                cFYI(1, ("GetSrvInodeNum rc %d", rc1));
-                               pinum = NULL;
-                               /* BB EOPNOSUPP disable SERVER_INUM? */
+                               fattr.cf_uniqueid = iunique(sb, ROOT_I);
+                               /* disable serverino if call not supported */
+                               if (rc1 == -EINVAL)
+                                       cifs_sb->mnt_cifs_flags &=
+                                                       ~CIFS_MOUNT_SERVER_INUM;
                        }
                } else {
-                       pinum = NULL;
-               }
-
-               *pinode = cifs_new_inode(sb, pinum);
-               if (*pinode == NULL) {
-                       rc = -ENOMEM;
-                       goto cgii_exit;
+                       fattr.cf_uniqueid = iunique(sb, ROOT_I);
                }
-       }
-       inode = *pinode;
-       cifsInfo = CIFS_I(inode);
-       cifsInfo->cifsAttrs = attr;
-       cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
-       cFYI(1, ("Old time %ld", cifsInfo->time));
-       cifsInfo->time = jiffies;
-       cFYI(1, ("New time %ld", cifsInfo->time));
-
-       /* blksize needs to be multiple of two. So safer to default to
-       blksize and blkbits set in superblock so 2**blkbits and blksize
-       will match rather than setting to:
-       (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
-
-       /* Linux can not store file creation time so ignore it */
-       if (pfindData->LastAccessTime)
-               inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
-       else /* do not need to use current_fs_time - time not stored */
-               inode->i_atime = CURRENT_TIME;
-       inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
-       inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
-       cFYI(DBG2, ("Attributes came in as 0x%x", attr));
-       if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
-               inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
-               inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
-       }
-
-       /* get default inode mode */
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set permission bits */
-       if (atomic_read(&cifsInfo->inUse) == 0 ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       inode->i_mode |= (S_IWUGO & default_mode);
-
-               inode->i_mode &= ~S_IFMT;
-       }
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               inode->i_mode &= ~S_IWUGO;
-
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               /* no need to fix endianness on 0 */
-               if (pfindData->EndOfFile == 0)
-                       inode->i_mode |= S_IFIFO;
-               else if (decode_sfu_inode(inode,
-                               le64_to_cpu(pfindData->EndOfFile),
-                               full_path, cifs_sb, xid))
-                       cFYI(1, ("unknown SFU file type\n"));
        } else {
-               if (attr & ATTR_DIRECTORY)
-                       inode->i_mode |= S_IFDIR;
-               else
-                       inode->i_mode |= S_IFREG;
+               fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
        }
 
-       cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
-       spin_lock(&inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
-               /* can not safely shrink the file size here if the
-                  client is writing to it due to potential races */
-               i_size_write(inode, cifsInfo->server_eof);
-
-               /* 512 bytes (2**9) is the fake blocksize that must be
-                  used for this calculation */
-               inode->i_blocks = (512 - 1 + le64_to_cpu(
-                                  pfindData->AllocationSize)) >> 9;
+       /* query for SFU type info if supported and needed */
+       if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
+           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+               tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
        }
-       spin_unlock(&inode->i_lock);
-
-       inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
-       /* BB fill in uid and gid here? with help from winbind?
-          or retrieve from NTFS stream extended attribute */
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                cFYI(1, ("Getting mode bits from ACL"));
-               acl_to_uid_mode(cifs_sb, inode, full_path, pfid);
+               cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
        }
 #endif
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-               /* fill in remaining high mode bits e.g. SUID, VTX */
-               get_sfu_mode(inode, full_path, cifs_sb, xid);
-       } else if (atomic_read(&cifsInfo->inUse) == 0) {
-               inode->i_uid = cifs_sb->mnt_uid;
-               inode->i_gid = cifs_sb->mnt_gid;
-               /* set so we do not keep refreshing these fields with
-                  bad data after user has changed them in memory */
-               atomic_set(&cifsInfo->inUse, 1);
-       }
-
-       cifs_set_ops(inode, is_dfs_referral);
-
 
+       /* fill in remaining high mode bits e.g. SUID, VTX */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
 
+       if (!*pinode) {
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode)
+                       rc = -ENOMEM;
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
+       }
 
 cgii_exit:
        kfree(buf);
@@ -695,33 +605,78 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
        return full_path;
 }
 
+static int
+cifs_find_inode(struct inode *inode, void *opaque)
+{
+       struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
+
+       if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
+               return 0;
+
+       return 1;
+}
+
+static int
+cifs_init_inode(struct inode *inode, void *opaque)
+{
+       struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
+
+       CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
+       return 0;
+}
+
+/* Given fattrs, get a corresponding inode */
+struct inode *
+cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
+{
+       unsigned long hash;
+       struct inode *inode;
+
+       cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
+
+       /* hash down to 32-bits on 32-bit arch */
+       hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
+
+       inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
+
+       /* we have fattrs in hand, update the inode */
+       if (inode) {
+               cifs_fattr_to_inode(inode, fattr);
+               if (sb->s_flags & MS_NOATIME)
+                       inode->i_flags |= S_NOATIME | S_NOCMTIME;
+               if (inode->i_state & I_NEW) {
+                       inode->i_ino = hash;
+                       unlock_new_inode(inode);
+               }
+       }
+
+       return inode;
+}
+
 /* gets root inode */
 struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 {
        int xid;
        struct cifs_sb_info *cifs_sb;
-       struct inode *inode;
+       struct inode *inode = NULL;
        long rc;
        char *full_path;
 
-       inode = iget_locked(sb, ino);
-       if (!inode)
-               return ERR_PTR(-ENOMEM);
-       if (!(inode->i_state & I_NEW))
-               return inode;
-
-       cifs_sb = CIFS_SB(inode->i_sb);
+       cifs_sb = CIFS_SB(sb);
        full_path = cifs_build_path_to_root(cifs_sb);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
        xid = GetXid();
        if (cifs_sb->tcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
-                                               xid);
+               rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
-               rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
+               rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                                xid, NULL);
+
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
        if (rc && cifs_sb->tcon->ipc) {
                cFYI(1, ("ipc connection - fake read inode"));
                inode->i_mode |= S_IFDIR;
@@ -737,7 +692,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
                return ERR_PTR(rc);
        }
 
-       unlock_new_inode(inode);
 
        kfree(full_path);
        /* can not call macro FreeXid here since in a void func
@@ -1063,44 +1017,6 @@ out_reval:
        return rc;
 }
 
-void posix_fill_in_inode(struct inode *tmp_inode,
-       FILE_UNIX_BASIC_INFO *pData, int isNewInode)
-{
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       cifsInfo->time = jiffies;
-       atomic_inc(&cifsInfo->inUse);
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       cifs_unix_info_to_inode(tmp_inode, pData, 1);
-       cifs_set_ops(tmp_inode, false);
-
-       if (!S_ISREG(tmp_inode->i_mode))
-               return;
-
-       /*
-        * No sense invalidating pages for new inode
-        * since we we have not started caching
-        * readahead file data yet.
-        */
-       if (isNewInode)
-               return;
-
-       if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-               (local_size == tmp_inode->i_size)) {
-               cFYI(1, ("inode exists but unchanged"));
-       } else {
-               /* file may have changed on server */
-               cFYI(1, ("invalidate inode, readdir detected change"));
-               invalidate_remote_inode(tmp_inode);
-       }
-}
-
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
        int rc = 0, tmprc;
@@ -1109,6 +1025,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
+       struct cifs_fattr fattr;
 
        cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
 
@@ -1148,7 +1065,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        cFYI(1, ("posix mkdir returned 0x%x", rc));
                        d_drop(direntry);
                } else {
-                       __u64 unique_id;
                        if (pInfo->Type == cpu_to_le32(-1)) {
                                /* no return info, go query for it */
                                kfree(pInfo);
@@ -1162,20 +1078,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        else
                                direntry->d_op = &cifs_dentry_ops;
 
-                       unique_id = le64_to_cpu(pInfo->UniqueId);
-                       newinode = cifs_new_inode(inode->i_sb, &unique_id);
-                       if (newinode == NULL) {
+                       cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
+                       newinode = cifs_iget(inode->i_sb, &fattr);
+                       if (!newinode) {
                                kfree(pInfo);
                                goto mkdir_get_info;
                        }
 
-                       newinode->i_nlink = 2;
                        d_instantiate(direntry, newinode);
 
-                       /* we already checked in POSIXCreate whether
-                          frame was long enough */
-                       posix_fill_in_inode(direntry->d_inode,
-                                       pInfo, 1 /* NewInode */);
 #ifdef CONFIG_CIFS_DEBUG2
                        cFYI(1, ("instantiated dentry %p %s to inode %p",
                                direntry, direntry->d_name.name, newinode));
@@ -1238,10 +1149,10 @@ mkdir_get_info:
                                args.uid = NO_CHANGE_64;
                                args.gid = NO_CHANGE_64;
                        }
-                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
-                                           cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags &
-                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+                                              cifs_sb->local_nls,
+                                              cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
                } else {
                        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
                            (mode & S_IWUGO) == 0) {
@@ -1622,6 +1533,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        if (!err) {
                generic_fillattr(dentry->d_inode, stat);
                stat->blksize = CIFS_MAX_MSGSIZE;
+               stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
        }
        return err;
 }
@@ -1786,6 +1698,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsTconInfo *pTcon = cifs_sb->tcon;
        struct cifs_unix_set_info_args *args = NULL;
+       struct cifsFileInfo *open_file;
 
        cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
                 direntry->d_name.name, attrs->ia_valid));
@@ -1872,10 +1785,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
-                               cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       open_file = find_writable_file(cifsInode);
+       if (open_file) {
+               u16 nfid = open_file->netfid;
+               u32 npid = open_file->pid;
+               rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
+               atomic_dec(&open_file->wrtPending);
+       } else {
+               rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
+                                   cifs_sb->local_nls,
+                                   cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+       }
 
        if (!rc)
                rc = inode_setattr(inode, attrs);
index 86d0055dc529906df58a3dfddbc4b5601af08d0f..f823a4a208a71b049499cfb4e3a5bf3191370a58 100644 (file)
@@ -63,374 +63,123 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
 }
 #endif /* DEBUG2 */
 
-/* Returns 1 if new inode created, 2 if both dentry and inode were */
-/* Might check in the future if inode number changed so we can rehash inode */
-static int
-construct_dentry(struct qstr *qstring, struct file *file,
-                struct inode **ptmp_inode, struct dentry **pnew_dentry,
-                __u64 *inum)
+/*
+ * Find the dentry that matches "name". If there isn't one, create one. If it's
+ * a negative dentry or the uniqueid changed, then drop it and recreate it.
+ */
+static struct dentry *
+cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
+                   struct cifs_fattr *fattr)
 {
-       struct dentry *tmp_dentry = NULL;
-       struct super_block *sb = file->f_path.dentry->d_sb;
-       int rc = 0;
+       struct dentry *dentry, *alias;
+       struct inode *inode;
+       struct super_block *sb = parent->d_inode->i_sb;
+
+       cFYI(1, ("For %s", name->name));
+
+       dentry = d_lookup(parent, name);
+       if (dentry) {
+               /* FIXME: check for inode number changes? */
+               if (dentry->d_inode != NULL)
+                       return dentry;
+               d_drop(dentry);
+               dput(dentry);
+       }
 
-       cFYI(1, ("For %s", qstring->name));
-
-       qstring->hash = full_name_hash(qstring->name, qstring->len);
-       tmp_dentry = d_lookup(file->f_path.dentry, qstring);
-       if (tmp_dentry) {
-               /* BB: overwrite old name? i.e. tmp_dentry->d_name and
-                * tmp_dentry->d_name.len??
-                */
-               cFYI(0, ("existing dentry with inode 0x%p",
-                        tmp_dentry->d_inode));
-               *ptmp_inode = tmp_dentry->d_inode;
-               if (*ptmp_inode == NULL) {
-                       *ptmp_inode = cifs_new_inode(sb, inum);
-                       if (*ptmp_inode == NULL)
-                               return rc;
-                       rc = 1;
-               }
-       } else {
-               tmp_dentry = d_alloc(file->f_path.dentry, qstring);
-               if (tmp_dentry == NULL) {
-                       cERROR(1, ("Failed allocating dentry"));
-                       *ptmp_inode = NULL;
-                       return rc;
-               }
+       dentry = d_alloc(parent, name);
+       if (dentry == NULL)
+               return NULL;
 
-               if (CIFS_SB(sb)->tcon->nocase)
-                       tmp_dentry->d_op = &cifs_ci_dentry_ops;
-               else
-                       tmp_dentry->d_op = &cifs_dentry_ops;
+       inode = cifs_iget(sb, fattr);
+       if (!inode) {
+               dput(dentry);
+               return NULL;
+       }
 
-               *ptmp_inode = cifs_new_inode(sb, inum);
-               if (*ptmp_inode == NULL)
-                       return rc;
-               rc = 2;
+       if (CIFS_SB(sb)->tcon->nocase)
+               dentry->d_op = &cifs_ci_dentry_ops;
+       else
+               dentry->d_op = &cifs_dentry_ops;
+
+       alias = d_materialise_unique(dentry, inode);
+       if (alias != NULL) {
+               dput(dentry);
+               if (IS_ERR(alias))
+                       return NULL;
+               dentry = alias;
        }
 
-       tmp_dentry->d_time = jiffies;
-       *pnew_dentry = tmp_dentry;
-       return rc;
+       return dentry;
 }
 
-static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
-                         char *buf, unsigned int *pobject_type, int isNewInode)
+static void
+cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 {
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-       __u32 attr;
-       __u64 allocation_size;
-       __u64 end_of_file;
-       umode_t default_mode;
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       if (new_buf_type) {
-               FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
-
-               attr = le32_to_cpu(pfindData->ExtFileAttributes);
-               allocation_size = le64_to_cpu(pfindData->AllocationSize);
-               end_of_file = le64_to_cpu(pfindData->EndOfFile);
-               tmp_inode->i_atime =
-                       cifs_NTtimeToUnix(pfindData->LastAccessTime);
-               tmp_inode->i_mtime =
-                       cifs_NTtimeToUnix(pfindData->LastWriteTime);
-               tmp_inode->i_ctime =
-                       cifs_NTtimeToUnix(pfindData->ChangeTime);
-       } else { /* legacy, OS2 and DOS style */
-               int offset = cifs_sb->tcon->ses->server->timeAdj;
-               FIND_FILE_STANDARD_INFO *pfindData =
-                       (FIND_FILE_STANDARD_INFO *)buf;
-
-               tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
-                                                   pfindData->LastAccessTime,
-                                                   offset);
-               tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               attr = le16_to_cpu(pfindData->Attributes);
-               allocation_size = le32_to_cpu(pfindData->AllocationSize);
-               end_of_file = le32_to_cpu(pfindData->DataSize);
-       }
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 
-       /* Linux can not store file creation time unfortunately so ignore it */
-
-       cifsInfo->cifsAttrs = attr;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
-               /* get more accurate mode via ACL - so force inode refresh */
-               cifsInfo->time = 0;
-       } else
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
-               cifsInfo->time = jiffies;
-
-       /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
-       /* 2767 perms - indicate mandatory locking */
-               /* BB fill in uid and gid here? with help from winbind?
-                  or retrieve from NTFS stream extended attribute */
-       if (atomic_read(&cifsInfo->inUse) == 0) {
-               tmp_inode->i_uid = cifs_sb->mnt_uid;
-               tmp_inode->i_gid = cifs_sb->mnt_gid;
-       }
-
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set initial permissions */
-       if ((atomic_read(&cifsInfo->inUse) == 0) ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               tmp_inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       tmp_inode->i_mode |= (S_IWUGO & default_mode);
-
-               tmp_inode->i_mode &= ~S_IFMT;
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
+       } else {
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
        }
 
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               tmp_inode->i_mode &= ~S_IWUGO;
+       if (fattr->cf_cifsattrs & ATTR_READONLY)
+               fattr->cf_mode &= ~S_IWUGO;
 
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               if (end_of_file == 0)  {
-                       tmp_inode->i_mode |= S_IFIFO;
-                       *pobject_type = DT_FIFO;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
+           fattr->cf_cifsattrs & ATTR_SYSTEM) {
+               if (fattr->cf_eof == 0)  {
+                       fattr->cf_mode &= ~S_IFMT;
+                       fattr->cf_mode |= S_IFIFO;
+                       fattr->cf_dtype = DT_FIFO;
                } else {
                        /*
-                        * trying to get the type can be slow, so just call
-                        * this a regular file for now, and mark for reval
+                        * trying to get the type and mode via SFU can be slow,
+                        * so just call those regular files for now, and mark
+                        * for reval
                         */
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
-                       cifsInfo->time = 0;
-               }
-       } else {
-               if (attr & ATTR_DIRECTORY) {
-                       tmp_inode->i_mode |= S_IFDIR;
-                       *pobject_type = DT_DIR;
-               } else {
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
                }
        }
+}
 
-       /* can not fill in nlink here as in qpathinfo version and Unx search */
-       if (atomic_read(&cifsInfo->inUse) == 0)
-               atomic_set(&cifsInfo->inUse, 1);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&tmp_inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the
-               client is writing to it due to potential races */
-               i_size_write(tmp_inode, end_of_file);
-
-       /* 512 bytes (2**9) is the fake blocksize that must be used */
-       /* for this calculation, even though the reported blocksize is larger */
-               tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
-       }
-       spin_unlock(&tmp_inode->i_lock);
-
-       if (allocation_size < end_of_file)
-               cFYI(1, ("May be sparse file, allocation less than file size"));
-       cFYI(1, ("File Size %ld and blocks %llu",
-               (unsigned long)tmp_inode->i_size,
-               (unsigned long long)tmp_inode->i_blocks));
-       if (S_ISREG(tmp_inode->i_mode)) {
-               cFYI(1, ("File inode"));
-               tmp_inode->i_op = &cifs_file_inode_ops;
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
-                       else
-                               tmp_inode->i_fop = &cifs_file_direct_ops;
-               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
-               else
-                       tmp_inode->i_fop = &cifs_file_ops;
-
-               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf <
-                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
-               else
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
-               if (isNewInode)
-                       return; /* No sense invalidating pages for new inode
-                                  since have not started caching readahead file
-                                  data yet */
-
-               if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-                       (local_size == tmp_inode->i_size)) {
-                       cFYI(1, ("inode exists but unchanged"));
-               } else {
-                       /* file may have changed on server */
-                       cFYI(1, ("invalidate inode, readdir detected change"));
-                       invalidate_remote_inode(tmp_inode);
-               }
-       } else if (S_ISDIR(tmp_inode->i_mode)) {
-               cFYI(1, ("Directory inode"));
-               tmp_inode->i_op = &cifs_dir_inode_ops;
-               tmp_inode->i_fop = &cifs_dir_ops;
-       } else if (S_ISLNK(tmp_inode->i_mode)) {
-               cFYI(1, ("Symbolic Link inode"));
-               tmp_inode->i_op = &cifs_symlink_inode_ops;
-       } else {
-               cFYI(1, ("Init special inode"));
-               init_special_inode(tmp_inode, tmp_inode->i_mode,
-                                  tmp_inode->i_rdev);
-       }
+void
+cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
+{
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+       fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       cifs_fill_common_info(fattr, cifs_sb);
 }
 
-static void unix_fill_in_inode(struct inode *tmp_inode,
-       FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
+void
+cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
 {
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-
-       __u32 type = le32_to_cpu(pfindData->Type);
-       __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
-       __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-       cifsInfo->time = jiffies;
-       atomic_inc(&cifsInfo->inUse);
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       tmp_inode->i_atime =
-           cifs_NTtimeToUnix(pfindData->LastAccessTime);
-       tmp_inode->i_mtime =
-           cifs_NTtimeToUnix(pfindData->LastModificationTime);
-       tmp_inode->i_ctime =
-           cifs_NTtimeToUnix(pfindData->LastStatusChange);
-
-       tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
-       /* since we set the inode type below we need to mask off type
-          to avoid strange results if bits above were corrupt */
-       tmp_inode->i_mode &= ~S_IFMT;
-       if (type == UNIX_FILE) {
-               *pobject_type = DT_REG;
-               tmp_inode->i_mode |= S_IFREG;
-       } else if (type == UNIX_SYMLINK) {
-               *pobject_type = DT_LNK;
-               tmp_inode->i_mode |= S_IFLNK;
-       } else if (type == UNIX_DIR) {
-               *pobject_type = DT_DIR;
-               tmp_inode->i_mode |= S_IFDIR;
-       } else if (type == UNIX_CHARDEV) {
-               *pobject_type = DT_CHR;
-               tmp_inode->i_mode |= S_IFCHR;
-               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-                               le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-       } else if (type == UNIX_BLOCKDEV) {
-               *pobject_type = DT_BLK;
-               tmp_inode->i_mode |= S_IFBLK;
-               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
-                               le64_to_cpu(pfindData->DevMinor) & MINORMASK);
-       } else if (type == UNIX_FIFO) {
-               *pobject_type = DT_FIFO;
-               tmp_inode->i_mode |= S_IFIFO;
-       } else if (type == UNIX_SOCKET) {
-               *pobject_type = DT_SOCK;
-               tmp_inode->i_mode |= S_IFSOCK;
-       } else {
-               /* safest to just call it a file */
-               *pobject_type = DT_REG;
-               tmp_inode->i_mode |= S_IFREG;
-               cFYI(1, ("unknown inode type %d", type));
-       }
+       int offset = cifs_sb->tcon->ses->server->timeAdj;
 
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
-               tmp_inode->i_uid = cifs_sb->mnt_uid;
-       else
-               tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
-               tmp_inode->i_gid = cifs_sb->mnt_gid;
-       else
-               tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
-       tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
-
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&tmp_inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the
-               client is writing to it due to potential races */
-               i_size_write(tmp_inode, end_of_file);
-
-       /* 512 bytes (2**9) is the fake blocksize that must be used */
-       /* for this calculation, not the real blocksize */
-               tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
-       }
-       spin_unlock(&tmp_inode->i_lock);
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
+                                           info->LastAccessTime, offset);
+       fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
+       fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
 
-       if (S_ISREG(tmp_inode->i_mode)) {
-               cFYI(1, ("File inode"));
-               tmp_inode->i_op = &cifs_file_inode_ops;
+       fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
+       fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
+       fattr->cf_eof = le32_to_cpu(info->DataSize);
 
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
-                       else
-                               tmp_inode->i_fop = &cifs_file_direct_ops;
-               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
-               else
-                       tmp_inode->i_fop = &cifs_file_ops;
-
-               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf <
-                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
-               else
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
-               if (isNewInode)
-                       return; /* No sense invalidating pages for new inode
-                                  since we have not started caching readahead
-                                  file data for it yet */
-
-               if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
-                       (local_size == tmp_inode->i_size)) {
-                       cFYI(1, ("inode exists but unchanged"));
-               } else {
-                       /* file may have changed on server */
-                       cFYI(1, ("invalidate inode, readdir detected change"));
-                       invalidate_remote_inode(tmp_inode);
-               }
-       } else if (S_ISDIR(tmp_inode->i_mode)) {
-               cFYI(1, ("Directory inode"));
-               tmp_inode->i_op = &cifs_dir_inode_ops;
-               tmp_inode->i_fop = &cifs_dir_ops;
-       } else if (S_ISLNK(tmp_inode->i_mode)) {
-               cFYI(1, ("Symbolic Link inode"));
-               tmp_inode->i_op = &cifs_symlink_inode_ops;
-/* tmp_inode->i_fop = *//* do not need to set to anything */
-       } else {
-               cFYI(1, ("Special inode"));
-               init_special_inode(tmp_inode, tmp_inode->i_mode,
-                                  tmp_inode->i_rdev);
-       }
+       cifs_fill_common_info(fattr, cifs_sb);
 }
 
 /* BB eventually need to add the following helper function to
@@ -872,7 +621,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
                        len = strnlen(filename, PATH_MAX);
                }
 
-               *pinum = le64_to_cpu(pFindData->UniqueId);
+               *pinum = le64_to_cpu(pFindData->basic.UniqueId);
        } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
                FILE_DIRECTORY_INFO *pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
@@ -932,11 +681,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        int rc = 0;
        struct qstr qstring;
        struct cifsFileInfo *pCifsF;
-       unsigned int obj_type;
-       __u64  inum;
+       u64    inum;
+       ino_t  ino;
+       struct super_block *sb;
        struct cifs_sb_info *cifs_sb;
-       struct inode *tmp_inode;
        struct dentry *tmp_dentry;
+       struct cifs_fattr fattr;
 
        /* get filename and len into qstring */
        /* get dentry */
@@ -954,60 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        if (rc != 0)
                return 0;
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       sb = file->f_path.dentry->d_sb;
+       cifs_sb = CIFS_SB(sb);
 
        qstring.name = scratch_buf;
        rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
                        pCifsF->srch_inf.info_level,
                        pCifsF->srch_inf.unicode, cifs_sb,
-                       max_len,
-                       &inum /* returned */);
+                       max_len, &inum /* returned */);
 
        if (rc)
                return rc;
 
-       /* only these two infolevels return valid inode numbers */
-       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
-           pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
-               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
-                                       &inum);
-       else
-               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
-                                       NULL);
-
-       if ((tmp_inode == NULL) || (tmp_dentry == NULL))
-               return -ENOMEM;
-
-       /* we pass in rc below, indicating whether it is a new inode,
-          so we can figure out whether to invalidate the inode cached
-          data if the file has changed */
        if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
-               unix_fill_in_inode(tmp_inode,
-                                  (FILE_UNIX_INFO *)pfindEntry,
-                                  &obj_type, rc);
+               cifs_unix_basic_to_fattr(&fattr,
+                                &((FILE_UNIX_INFO *) pfindEntry)->basic,
+                                cifs_sb);
        else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
-               fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
-                               pfindEntry, &obj_type, rc);
+               cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
+                                       pfindEntry, cifs_sb);
        else
-               fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+               cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
+                                       pfindEntry, cifs_sb);
 
-       if (rc) /* new inode - needs to be tied to dentry */ {
-               d_instantiate(tmp_dentry, tmp_inode);
-               if (rc == 2)
-                       d_rehash(tmp_dentry);
-       }
+       /* FIXME: make _to_fattr functions fill this out */
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
+               fattr.cf_uniqueid = inum;
+       else
+               fattr.cf_uniqueid = iunique(sb, ROOT_I);
 
+       ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
+       tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
 
        rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
-                    tmp_inode->i_ino, obj_type);
+                    ino, fattr.cf_dtype);
+
+       /*
+        * we can not return filldir errors to the caller since they are
+        * "normal" when the stat blocksize is too small - we return remapped
+        * error instead
+        *
+        * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
+        * case already. Why should we be clobbering other errors from it?
+        */
        if (rc) {
                cFYI(1, ("filldir rc = %d", rc));
-               /* we can not return filldir errors to the caller
-               since they are "normal" when the stat blocksize
-               is too small - we return remapped error instead */
                rc = -EOVERFLOW;
        }
-
        dput(tmp_dentry);
        return rc;
 }
index fbadb947727b1e1e3bcee65bd0db72c2e8ee2e18..94502dab972af5ad4d2bd558f50f896cd8a35db3 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/smb_mount.h>
 #include <linux/ncp_mount.h>
 #include <linux/nfs4_mount.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
index 626c7483b4de4e4f076bd4ab07af690007f9a0ae..f28f070a60fc3b30addbfe50d6e250df734a9879 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_bridge.h>
index 205ec95b347e3001b6cb4358b8c6539802d95bed..eb507c453c5ff7ca221f933619a085461bec3300 100644 (file)
@@ -435,7 +435,7 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
 static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
                    unsigned int flags, struct dlm_rsb **r_ret)
 {
-       struct dlm_rsb *r, *tmp;
+       struct dlm_rsb *r = NULL, *tmp;
        uint32_t hash, bucket;
        int error = -EINVAL;
 
index cdb580a9c7a28352e903fa660c848826966b9dc1..618a60f03886bf75118cefbe1fa113c1733e6baf 100644 (file)
@@ -902,7 +902,7 @@ static void tcp_connect_to_sock(struct connection *con)
        int result = -EHOSTUNREACH;
        struct sockaddr_storage saddr, src_addr;
        int addr_len;
-       struct socket *sock;
+       struct socket *sock = NULL;
 
        if (con->nodeid == 0) {
                log_print("attempt to connect sock 0 foiled");
@@ -962,6 +962,8 @@ out_err:
        if (con->sock) {
                sock_release(con->sock);
                con->sock = NULL;
+       } else if (sock) {
+               sock_release(sock);
        }
        /*
         * Some errors are fatal and this list might need adjusting. For other
index 894a32d438d5094bb9f1882825f5f01f12f096d7..16f682e26c07e49493e8a667a6b36cf0cf9f6bb6 100644 (file)
@@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 {
        struct dlm_plock_info info;
        struct plock_op *op;
-       int found = 0;
+       int found = 0, do_callback = 0;
 
        if (count != sizeof(info))
                return -EINVAL;
@@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 
        spin_lock(&ops_lock);
        list_for_each_entry(op, &recv_list, list) {
-               if (op->info.fsid == info.fsid && op->info.number == info.number &&
+               if (op->info.fsid == info.fsid &&
+                   op->info.number == info.number &&
                    op->info.owner == info.owner) {
+                       struct plock_xop *xop = (struct plock_xop *)op;
                        list_del_init(&op->list);
-                       found = 1;
-                       op->done = 1;
                        memcpy(&op->info, &info, sizeof(info));
+                       if (xop->callback)
+                               do_callback = 1;
+                       else
+                               op->done = 1;
+                       found = 1;
                        break;
                }
        }
        spin_unlock(&ops_lock);
 
        if (found) {
-               struct plock_xop *xop;
-               xop = (struct plock_xop *)op;
-               if (xop->callback)
+               if (do_callback)
                        dlm_plock_callback(op);
                else
                        wake_up(&recv_wq);
index af737bb56cb71942ebed99c9bad8eb6a34bdaeb8..259525c9abb8c0296f19fa3dc340b9ac29e70acd 100644 (file)
@@ -1303,6 +1303,13 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
        }
        (*new_auth_tok)->session_key.encrypted_key_size =
                (body_size - (ECRYPTFS_SALT_SIZE + 5));
+       if ((*new_auth_tok)->session_key.encrypted_key_size
+           > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
+               printk(KERN_WARNING "Tag 3 packet contains key larger "
+                      "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
+               rc = -EINVAL;
+               goto out_free;
+       }
        if (unlikely(data[(*packet_size)++] != 0x04)) {
                printk(KERN_WARNING "Unknown version number [%d]\n",
                       data[(*packet_size) - 1]);
@@ -1449,6 +1456,12 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
                rc = -EINVAL;
                goto out;
        }
+       if (unlikely((*tag_11_contents_size) > max_contents_bytes)) {
+               printk(KERN_ERR "Literal data section in tag 11 packet exceeds "
+                      "expected size\n");
+               rc = -EINVAL;
+               goto out;
+       }
        if (data[(*packet_size)++] != 0x62) {
                printk(KERN_WARNING "Unrecognizable packet\n");
                rc = -EINVAL;
index 24667eedc02329554735f72420cbc04d99faa871..c6718e4817feab5e56a2903b409493a458d3de84 100644 (file)
@@ -2,9 +2,7 @@
  * common.h - Common definitions for both Kernel and user-mode utilities
  *
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 65b0c8c776a1db8144c74ce0d7074512da882b51..4cfab1cc75c03a0bb7654e5c8150c2009fe4aa11 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 0fd4c7859679390e11eac05838ec5d35e6718c74..5ec72e020b22bb8fcbb1f08d1df4af037ab179bd 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -156,6 +154,9 @@ ino_t exofs_parent_ino(struct dentry *child);
 int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
                    struct inode *);
 
+/* super.c               */
+int exofs_sync_fs(struct super_block *sb, int wait);
+
 /*********************
  * operation vectors *
  *********************/
index 6ed7fe4847522db1f7766528478d6b508ad64af7..839b9dc1e70f3f6663a428e2d48938f6aadfcb0c 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -47,16 +45,23 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
 {
        int ret;
        struct address_space *mapping = filp->f_mapping;
+       struct inode *inode = dentry->d_inode;
+       struct super_block *sb;
 
        ret = filemap_write_and_wait(mapping);
        if (ret)
                return ret;
 
-       /*Note: file_fsync below also calles sync_blockdev, which is a no-op
-        *      for exofs, but other then that it does sync_inode and
-        *      sync_superblock which is what we need here.
-        */
-       return file_fsync(filp, dentry, datasync);
+       /* sync the inode attributes */
+       ret = write_inode_now(inode, 1);
+
+       /* This is a good place to write the sb */
+       /* TODO: Sechedule an sb-sync on create */
+       sb = inode->i_sb;
+       if (sb->s_dirt)
+               exofs_sync_fs(sb, 1);
+
+       return ret;
 }
 
 static int exofs_flush(struct file *file, fl_owner_t id)
index 77d0a295eb1cd3e95443da014fc9801cf64f5aff..6c10f7476699c4da76b18453a844aefcaa6c9f09 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -295,6 +293,9 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
 err:
        if (!is_sync)
                _unlock_pcol_pages(pcol, ret, READ);
+       else /* Pages unlocked by caller in sync mode only free bio */
+               pcol_free(pcol);
+
        kfree(pcol_copy);
        if (or)
                osd_end_request(or);
index 77fdd765e76d13300432de102a7b19986da6fc09..b7dd0c23686376822ffd40c185bc9b1683796d31 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index b3d2ccb87aaa8981374e824066bfd2aa608fa86a..4372542df284ed8336a86f6ce205f9465980e707 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 8216c5b77b5325db78970efc711ab3729a1ea46e..5ab10c3bbebec0dd1ba2ab81c340b6be415dcafd 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
@@ -33,6 +31,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/vfs.h>
@@ -200,7 +199,7 @@ static const struct export_operations exofs_export_ops;
 /*
  * Write the superblock to the OSD
  */
-static int exofs_sync_fs(struct super_block *sb, int wait)
+int exofs_sync_fs(struct super_block *sb, int wait)
 {
        struct exofs_sb_info *sbi;
        struct exofs_fscb *fscb;
index 36e2d7bc7f7bd2a93eb8363b7b9b31801732e60f..4dd687c3e74740f57b9ea4180859ed34f57da8cc 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * Copyright (C) 2005, 2006
- * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
- * Copyright (C) 2005, 2006
- * International Business Machines
+ * Avishay Traeger (avishay@gmail.com)
  * Copyright (C) 2008, 2009
  * Boaz Harrosh <bharrosh@panasas.com>
  *
index 7cb4badef927433ec90618b67c69cc08bec936f1..e7431309bdca9b7c873a34718263f14097b81ff5 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/compat.h>
 #include <linux/mount.h>
-#include <linux/smp_lock.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
index 3d724a95882f618672a45ee8f945d9164f80b89f..373fa90c796a0821c23cd441c0a238a1a52cfb69 100644 (file)
@@ -130,8 +130,7 @@ static int ext3_readdir(struct file * filp,
                struct buffer_head *bh = NULL;
 
                map_bh.b_state = 0;
-               err = ext3_get_blocks_handle(NULL, inode, blk, 1,
-                                               &map_bh, 0, 0);
+               err = ext3_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0);
                if (err > 0) {
                        pgoff_t index = map_bh.b_blocknr >>
                                        (PAGE_CACHE_SHIFT - inode->i_blkbits);
index 5f51fed5c750870b8c575fdf7dd8e877fe986bfb..b49908a167ae09d366f76ddcef57432f338b5735 100644 (file)
@@ -788,7 +788,7 @@ err_out:
 int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
                sector_t iblock, unsigned long maxblocks,
                struct buffer_head *bh_result,
-               int create, int extend_disksize)
+               int create)
 {
        int err = -EIO;
        int offsets[4];
@@ -911,13 +911,6 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (!err)
                err = ext3_splice_branch(handle, inode, iblock,
                                        partial, indirect_blks, count);
-       /*
-        * i_disksize growing is protected by truncate_mutex.  Don't forget to
-        * protect it if you're about to implement concurrent
-        * ext3_get_block() -bzzz
-       */
-       if (!err && extend_disksize && inode->i_size > ei->i_disksize)
-               ei->i_disksize = inode->i_size;
        mutex_unlock(&ei->truncate_mutex);
        if (err)
                goto cleanup;
@@ -972,7 +965,7 @@ static int ext3_get_block(struct inode *inode, sector_t iblock,
        }
 
        ret = ext3_get_blocks_handle(handle, inode, iblock,
-                                       max_blocks, bh_result, create, 0);
+                                       max_blocks, bh_result, create);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -1005,7 +998,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode,
        dummy.b_blocknr = -1000;
        buffer_trace_init(&dummy.b_history);
        err = ext3_get_blocks_handle(handle, inode, block, 1,
-                                       &dummy, create, 1);
+                                       &dummy, create);
        /*
         * ext3_get_blocks_handle() returns number of blocks
         * mapped. 0 in case of a HOLE.
@@ -1193,15 +1186,16 @@ write_begin_failed:
                 * i_size_read because we hold i_mutex.
                 *
                 * Add inode to orphan list in case we crash before truncate
-                * finishes.
+                * finishes. Do this only if ext3_can_truncate() agrees so
+                * that orphan processing code is happy.
                 */
-               if (pos + len > inode->i_size)
+               if (pos + len > inode->i_size && ext3_can_truncate(inode))
                        ext3_orphan_add(handle, inode);
                ext3_journal_stop(handle);
                unlock_page(page);
                page_cache_release(page);
                if (pos + len > inode->i_size)
-                       vmtruncate(inode, inode->i_size);
+                       ext3_truncate(inode);
        }
        if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
@@ -1287,7 +1281,7 @@ static int ext3_ordered_write_end(struct file *file,
         * There may be allocated blocks outside of i_size because
         * we failed to copy some data. Prepare for truncate.
         */
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext3_can_truncate(inode))
                ext3_orphan_add(handle, inode);
        ret2 = ext3_journal_stop(handle);
        if (!ret)
@@ -1296,7 +1290,7 @@ static int ext3_ordered_write_end(struct file *file,
        page_cache_release(page);
 
        if (pos + len > inode->i_size)
-               vmtruncate(inode, inode->i_size);
+               ext3_truncate(inode);
        return ret ? ret : copied;
 }
 
@@ -1315,14 +1309,14 @@ static int ext3_writeback_write_end(struct file *file,
         * There may be allocated blocks outside of i_size because
         * we failed to copy some data. Prepare for truncate.
         */
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext3_can_truncate(inode))
                ext3_orphan_add(handle, inode);
        ret = ext3_journal_stop(handle);
        unlock_page(page);
        page_cache_release(page);
 
        if (pos + len > inode->i_size)
-               vmtruncate(inode, inode->i_size);
+               ext3_truncate(inode);
        return ret ? ret : copied;
 }
 
@@ -1358,7 +1352,7 @@ static int ext3_journalled_write_end(struct file *file,
         * There may be allocated blocks outside of i_size because
         * we failed to copy some data. Prepare for truncate.
         */
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext3_can_truncate(inode))
                ext3_orphan_add(handle, inode);
        EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
        if (inode->i_size > EXT3_I(inode)->i_disksize) {
@@ -1375,7 +1369,7 @@ static int ext3_journalled_write_end(struct file *file,
        page_cache_release(page);
 
        if (pos + len > inode->i_size)
-               vmtruncate(inode, inode->i_size);
+               ext3_truncate(inode);
        return ret ? ret : copied;
 }
 
index 0ddf7e55abe181e3ac1bd31fea3357bf4c1bf8a6..9714db393efe8a1b6fa2ff0b2e7cf36fb7ecc199 100644 (file)
@@ -93,20 +93,20 @@ typedef unsigned int ext4_group_t;
 struct ext4_allocation_request {
        /* target inode for block we're allocating */
        struct inode *inode;
+       /* how many blocks we want to allocate */
+       unsigned int len;
        /* logical block in target inode */
        ext4_lblk_t logical;
-       /* phys. target (a hint) */
-       ext4_fsblk_t goal;
        /* the closest logical allocated block to the left */
        ext4_lblk_t lleft;
-       /* phys. block for ^^^ */
-       ext4_fsblk_t pleft;
        /* the closest logical allocated block to the right */
        ext4_lblk_t lright;
-       /* phys. block for ^^^ */
+       /* phys. target (a hint) */
+       ext4_fsblk_t goal;
+       /* phys. block for the closest logical allocated block to the left */
+       ext4_fsblk_t pleft;
+       /* phys. block for the closest logical allocated block to the right */
        ext4_fsblk_t pright;
-       /* how many blocks we want to allocate */
-       unsigned int len;
        /* flags. see above EXT4_MB_HINT_* */
        unsigned int flags;
 };
index ad13a84644e1ff94000dda0ab8bbe09f05a417e7..eb27fd0f2ee86dd4c8badd2ed146f2a306e1f35f 100644 (file)
@@ -43,6 +43,8 @@ int __ext4_journal_forget(const char *where, handle_t *handle,
                        ext4_journal_abort_handle(where, __func__, bh,
                                                  handle, err);
        }
+       else
+               brelse(bh);
        return err;
 }
 
@@ -57,6 +59,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle,
                        ext4_journal_abort_handle(where, __func__, bh,
                                                  handle, err);
        }
+       else
+               brelse(bh);
        return err;
 }
 
index be2f426f680538065b86aac16bb1f2f822a49a48..139fb8cb87e40dabf2538ff28d163849ed8d2bfa 100644 (file)
@@ -131,9 +131,11 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
 int __ext4_journal_get_write_access(const char *where, handle_t *handle,
                                struct buffer_head *bh);
 
+/* When called with an invalid handle, this will still do a put on the BH */
 int __ext4_journal_forget(const char *where, handle_t *handle,
                                struct buffer_head *bh);
 
+/* When called with an invalid handle, this will still do a put on the BH */
 int __ext4_journal_revoke(const char *where, handle_t *handle,
                                ext4_fsblk_t blocknr, struct buffer_head *bh);
 
@@ -281,10 +283,10 @@ static inline int ext4_should_order_data(struct inode *inode)
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-       if (EXT4_JOURNAL(inode) == NULL)
-               return 0;
        if (!S_ISREG(inode->i_mode))
                return 0;
+       if (EXT4_JOURNAL(inode) == NULL)
+               return 1;
        if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
index 50322a09bd01af54d66cf2d344765b8b92075332..73ebfb44ad750f0405976f7ff6c792936edb0765 100644 (file)
@@ -1977,6 +1977,7 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks,
                         */
                        /* 1 bitmap, 1 block group descriptor */
                        ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb);
+                       return ret;
                }
        }
 
index 2f645732e3b76ef84e76f58761c16116825c2763..29e6dc7299b8b6186cf46a39deac0a88594b6028 100644 (file)
@@ -833,7 +833,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
        if (!goal)
                goal = sbi->s_inode_goal;
 
-       if (goal && goal < le32_to_cpu(sbi->s_es->s_inodes_count)) {
+       if (goal && goal <= le32_to_cpu(sbi->s_es->s_inodes_count)) {
                group = (goal - 1) / EXT4_INODES_PER_GROUP(sb);
                ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb);
                ret2 = 0;
index 60a26f3a6f8bd3e2ac5db8cfc220538630b7de6a..f9c642b22efabb56f5ec3ae109bf2eaf75beee8a 100644 (file)
@@ -78,16 +78,14 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
  * but there may still be a record of it in the journal, and that record
  * still needs to be revoked.
  *
- * If the handle isn't valid we're not journaling so there's nothing to do.
+ * If the handle isn't valid we're not journaling, but we still need to
+ * call into ext4_journal_revoke() to put the buffer head.
  */
 int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
                struct buffer_head *bh, ext4_fsblk_t blocknr)
 {
        int err;
 
-       if (!ext4_handle_valid(handle))
-               return 0;
-
        might_sleep();
 
        BUFFER_TRACE(bh, "enter");
@@ -1513,14 +1511,14 @@ retry:
                 * Add inode to orphan list in case we crash before
                 * truncate finishes
                 */
-               if (pos + len > inode->i_size)
+               if (pos + len > inode->i_size && ext4_can_truncate(inode))
                        ext4_orphan_add(handle, inode);
 
                ext4_journal_stop(handle);
                if (pos + len > inode->i_size) {
-                       vmtruncate(inode, inode->i_size);
+                       ext4_truncate(inode);
                        /*
-                        * If vmtruncate failed early the inode might
+                        * If truncate failed early the inode might
                         * still be on the orphan list; we need to
                         * make sure the inode is removed from the
                         * orphan list in that case.
@@ -1614,7 +1612,7 @@ static int ext4_ordered_write_end(struct file *file,
                ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
                copied = ret2;
-               if (pos + len > inode->i_size)
+               if (pos + len > inode->i_size && ext4_can_truncate(inode))
                        /* if we have allocated more blocks and copied
                         * less. We will have blocks allocated outside
                         * inode->i_size. So truncate them
@@ -1628,9 +1626,9 @@ static int ext4_ordered_write_end(struct file *file,
                ret = ret2;
 
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -1655,7 +1653,7 @@ static int ext4_writeback_write_end(struct file *file,
        ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
        copied = ret2;
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext4_can_truncate(inode))
                /* if we have allocated more blocks and copied
                 * less. We will have blocks allocated outside
                 * inode->i_size. So truncate them
@@ -1670,9 +1668,9 @@ static int ext4_writeback_write_end(struct file *file,
                ret = ret2;
 
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -1722,7 +1720,7 @@ static int ext4_journalled_write_end(struct file *file,
 
        unlock_page(page);
        page_cache_release(page);
-       if (pos + len > inode->i_size)
+       if (pos + len > inode->i_size && ext4_can_truncate(inode))
                /* if we have allocated more blocks and copied
                 * less. We will have blocks allocated outside
                 * inode->i_size. So truncate them
@@ -1733,9 +1731,9 @@ static int ext4_journalled_write_end(struct file *file,
        if (!ret)
                ret = ret2;
        if (pos + len > inode->i_size) {
-               vmtruncate(inode, inode->i_size);
+               ext4_truncate(inode);
                /*
-                * If vmtruncate failed early the inode might still be
+                * If truncate failed early the inode might still be
                 * on the orphan list; we need to make sure the inode
                 * is removed from the orphan list in that case.
                 */
@@ -2305,15 +2303,9 @@ flush_it:
        return;
 }
 
-static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
+static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh)
 {
-       /*
-        * unmapped buffer is possible for holes.
-        * delay buffer is possible with delayed allocation.
-        * We also need to consider unwritten buffer as unmapped.
-        */
-       return (!buffer_mapped(bh) || buffer_delay(bh) ||
-                               buffer_unwritten(bh)) && buffer_dirty(bh);
+       return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh);
 }
 
 /*
@@ -2398,9 +2390,9 @@ static int __mpage_da_writepage(struct page *page,
                         * We need to try to allocate
                         * unmapped blocks in the same page.
                         * Otherwise we won't make progress
-                        * with the page in ext4_da_writepage
+                        * with the page in ext4_writepage
                         */
-                       if (ext4_bh_unmapped_or_delay(NULL, bh)) {
+                       if (ext4_bh_delay_or_unwritten(NULL, bh)) {
                                mpage_add_bh_to_extent(mpd, logical,
                                                       bh->b_size,
                                                       bh->b_state);
@@ -2517,7 +2509,6 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
         * so call get_block_wrap with create = 0
         */
        ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0);
-       BUG_ON(create && ret == 0);
        if (ret > 0) {
                bh_result->b_size = (ret << inode->i_blkbits);
                ret = 0;
@@ -2525,15 +2516,102 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
        return ret;
 }
 
+static int bget_one(handle_t *handle, struct buffer_head *bh)
+{
+       get_bh(bh);
+       return 0;
+}
+
+static int bput_one(handle_t *handle, struct buffer_head *bh)
+{
+       put_bh(bh);
+       return 0;
+}
+
+static int __ext4_journalled_writepage(struct page *page,
+                                      struct writeback_control *wbc,
+                                      unsigned int len)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct buffer_head *page_bufs;
+       handle_t *handle = NULL;
+       int ret = 0;
+       int err;
+
+       page_bufs = page_buffers(page);
+       BUG_ON(!page_bufs);
+       walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one);
+       /* As soon as we unlock the page, it can go away, but we have
+        * references to buffers so we are safe */
+       unlock_page(page);
+
+       handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               goto out;
+       }
+
+       ret = walk_page_buffers(handle, page_bufs, 0, len, NULL,
+                               do_journal_get_write_access);
+
+       err = walk_page_buffers(handle, page_bufs, 0, len, NULL,
+                               write_end_fn);
+       if (ret == 0)
+               ret = err;
+       err = ext4_journal_stop(handle);
+       if (!ret)
+               ret = err;
+
+       walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one);
+       EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
+out:
+       return ret;
+}
+
 /*
+ * Note that we don't need to start a transaction unless we're journaling data
+ * because we should have holes filled from ext4_page_mkwrite(). We even don't
+ * need to file the inode to the transaction's list in ordered mode because if
+ * we are writing back data added by write(), the inode is already there and if
+ * we are writing back data modified via mmap(), noone guarantees in which
+ * transaction the data will hit the disk. In case we are journaling data, we
+ * cannot start transaction directly because transaction start ranks above page
+ * lock so we have to do some magic.
+ *
  * This function can get called via...
  *   - ext4_da_writepages after taking page lock (have journal handle)
  *   - journal_submit_inode_data_buffers (no journal handle)
  *   - shrink_page_list via pdflush (no journal handle)
  *   - grab_page_cache when doing write_begin (have journal handle)
+ *
+ * We don't do any block allocation in this function. If we have page with
+ * multiple blocks we need to write those buffer_heads that are mapped. This
+ * is important for mmaped based write. So if we do with blocksize 1K
+ * truncate(f, 1024);
+ * a = mmap(f, 0, 4096);
+ * a[0] = 'a';
+ * truncate(f, 4096);
+ * we have in the page first buffer_head mapped via page_mkwrite call back
+ * but other bufer_heads would be unmapped but dirty(dirty done via the
+ * do_wp_page). So writepage should write the first block. If we modify
+ * the mmap area beyond 1024 we will again get a page_fault and the
+ * page_mkwrite callback will do the block allocation and mark the
+ * buffer_heads mapped.
+ *
+ * We redirty the page if we have any buffer_heads that is either delay or
+ * unwritten in the page.
+ *
+ * We can get recursively called as show below.
+ *
+ *     ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
+ *             ext4_writepage()
+ *
+ * But since we don't do any block allocation we should not deadlock.
+ * Page also have the dirty flag cleared so we don't get recurive page_lock.
  */
-static int ext4_da_writepage(struct page *page,
-                               struct writeback_control *wbc)
+static int ext4_writepage(struct page *page,
+                         struct writeback_control *wbc)
 {
        int ret = 0;
        loff_t size;
@@ -2541,7 +2619,7 @@ static int ext4_da_writepage(struct page *page,
        struct buffer_head *page_bufs;
        struct inode *inode = page->mapping->host;
 
-       trace_ext4_da_writepage(inode, page);
+       trace_ext4_writepage(inode, page);
        size = i_size_read(inode);
        if (page->index == size >> PAGE_CACHE_SHIFT)
                len = size & ~PAGE_CACHE_MASK;
@@ -2551,7 +2629,7 @@ static int ext4_da_writepage(struct page *page,
        if (page_has_buffers(page)) {
                page_bufs = page_buffers(page);
                if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay)) {
+                                       ext4_bh_delay_or_unwritten)) {
                        /*
                         * We don't want to do  block allocation
                         * So redirty the page and return
@@ -2578,13 +2656,13 @@ static int ext4_da_writepage(struct page *page,
                 * all are mapped and non delay. We don't want to
                 * do block allocation here.
                 */
-               ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
+               ret = block_prepare_write(page, 0, len,
                                          noalloc_get_block_write);
                if (!ret) {
                        page_bufs = page_buffers(page);
                        /* check whether all are mapped and non delay */
                        if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
-                                               ext4_bh_unmapped_or_delay)) {
+                                               ext4_bh_delay_or_unwritten)) {
                                redirty_page_for_writepage(wbc, page);
                                unlock_page(page);
                                return 0;
@@ -2600,7 +2678,16 @@ static int ext4_da_writepage(struct page *page,
                        return 0;
                }
                /* now mark the buffer_heads as dirty and uptodate */
-               block_commit_write(page, 0, PAGE_CACHE_SIZE);
+               block_commit_write(page, 0, len);
+       }
+
+       if (PageChecked(page) && ext4_should_journal_data(inode)) {
+               /*
+                * It's mmapped pagecache.  Add buffers and journal it.  There
+                * doesn't seem much point in redirtying the page here.
+                */
+               ClearPageChecked(page);
+               return __ext4_journalled_writepage(page, wbc, len);
        }
 
        if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
@@ -2907,7 +2994,7 @@ retry:
                 * i_size_read because we hold i_mutex.
                 */
                if (pos + len > inode->i_size)
-                       vmtruncate(inode, inode->i_size);
+                       ext4_truncate(inode);
        }
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -3130,222 +3217,6 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, ext4_get_block);
 }
 
-static int bget_one(handle_t *handle, struct buffer_head *bh)
-{
-       get_bh(bh);
-       return 0;
-}
-
-static int bput_one(handle_t *handle, struct buffer_head *bh)
-{
-       put_bh(bh);
-       return 0;
-}
-
-/*
- * Note that we don't need to start a transaction unless we're journaling data
- * because we should have holes filled from ext4_page_mkwrite(). We even don't
- * need to file the inode to the transaction's list in ordered mode because if
- * we are writing back data added by write(), the inode is already there and if
- * we are writing back data modified via mmap(), noone guarantees in which
- * transaction the data will hit the disk. In case we are journaling data, we
- * cannot start transaction directly because transaction start ranks above page
- * lock so we have to do some magic.
- *
- * In all journaling modes block_write_full_page() will start the I/O.
- *
- * Problem:
- *
- *     ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
- *             ext4_writepage()
- *
- * Similar for:
- *
- *     ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ...
- *
- * Same applies to ext4_get_block().  We will deadlock on various things like
- * lock_journal and i_data_sem
- *
- * Setting PF_MEMALLOC here doesn't work - too many internal memory
- * allocations fail.
- *
- * 16May01: If we're reentered then journal_current_handle() will be
- *         non-zero. We simply *return*.
- *
- * 1 July 2001: @@@ FIXME:
- *   In journalled data mode, a data buffer may be metadata against the
- *   current transaction.  But the same file is part of a shared mapping
- *   and someone does a writepage() on it.
- *
- *   We will move the buffer onto the async_data list, but *after* it has
- *   been dirtied. So there's a small window where we have dirty data on
- *   BJ_Metadata.
- *
- *   Note that this only applies to the last partial page in the file.  The
- *   bit which block_write_full_page() uses prepare/commit for.  (That's
- *   broken code anyway: it's wrong for msync()).
- *
- *   It's a rare case: affects the final partial page, for journalled data
- *   where the file is subject to bith write() and writepage() in the same
- *   transction.  To fix it we'll need a custom block_write_full_page().
- *   We'll probably need that anyway for journalling writepage() output.
- *
- * We don't honour synchronous mounts for writepage().  That would be
- * disastrous.  Any write() or metadata operation will sync the fs for
- * us.
- *
- */
-static int __ext4_normal_writepage(struct page *page,
-                                  struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-
-       if (test_opt(inode->i_sb, NOBH))
-               return nobh_writepage(page, noalloc_get_block_write, wbc);
-       else
-               return block_write_full_page(page, noalloc_get_block_write,
-                                            wbc);
-}
-
-static int ext4_normal_writepage(struct page *page,
-                                struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       loff_t size = i_size_read(inode);
-       loff_t len;
-
-       trace_ext4_normal_writepage(inode, page);
-       J_ASSERT(PageLocked(page));
-       if (page->index == size >> PAGE_CACHE_SHIFT)
-               len = size & ~PAGE_CACHE_MASK;
-       else
-               len = PAGE_CACHE_SIZE;
-
-       if (page_has_buffers(page)) {
-               /* if page has buffers it should all be mapped
-                * and allocated. If there are not buffers attached
-                * to the page we know the page is dirty but it lost
-                * buffers. That means that at some moment in time
-                * after write_begin() / write_end() has been called
-                * all buffers have been clean and thus they must have been
-                * written at least once. So they are all mapped and we can
-                * happily proceed with mapping them and writing the page.
-                */
-               BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay));
-       }
-
-       if (!ext4_journal_current_handle())
-               return __ext4_normal_writepage(page, wbc);
-
-       redirty_page_for_writepage(wbc, page);
-       unlock_page(page);
-       return 0;
-}
-
-static int __ext4_journalled_writepage(struct page *page,
-                                      struct writeback_control *wbc)
-{
-       struct address_space *mapping = page->mapping;
-       struct inode *inode = mapping->host;
-       struct buffer_head *page_bufs;
-       handle_t *handle = NULL;
-       int ret = 0;
-       int err;
-
-       ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
-                                 noalloc_get_block_write);
-       if (ret != 0)
-               goto out_unlock;
-
-       page_bufs = page_buffers(page);
-       walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL,
-                                                               bget_one);
-       /* As soon as we unlock the page, it can go away, but we have
-        * references to buffers so we are safe */
-       unlock_page(page);
-
-       handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               goto out;
-       }
-
-       ret = walk_page_buffers(handle, page_bufs, 0,
-                       PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
-
-       err = walk_page_buffers(handle, page_bufs, 0,
-                               PAGE_CACHE_SIZE, NULL, write_end_fn);
-       if (ret == 0)
-               ret = err;
-       err = ext4_journal_stop(handle);
-       if (!ret)
-               ret = err;
-
-       walk_page_buffers(handle, page_bufs, 0,
-                               PAGE_CACHE_SIZE, NULL, bput_one);
-       EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
-       goto out;
-
-out_unlock:
-       unlock_page(page);
-out:
-       return ret;
-}
-
-static int ext4_journalled_writepage(struct page *page,
-                                    struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       loff_t size = i_size_read(inode);
-       loff_t len;
-
-       trace_ext4_journalled_writepage(inode, page);
-       J_ASSERT(PageLocked(page));
-       if (page->index == size >> PAGE_CACHE_SHIFT)
-               len = size & ~PAGE_CACHE_MASK;
-       else
-               len = PAGE_CACHE_SIZE;
-
-       if (page_has_buffers(page)) {
-               /* if page has buffers it should all be mapped
-                * and allocated. If there are not buffers attached
-                * to the page we know the page is dirty but it lost
-                * buffers. That means that at some moment in time
-                * after write_begin() / write_end() has been called
-                * all buffers have been clean and thus they must have been
-                * written at least once. So they are all mapped and we can
-                * happily proceed with mapping them and writing the page.
-                */
-               BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
-                                       ext4_bh_unmapped_or_delay));
-       }
-
-       if (ext4_journal_current_handle())
-               goto no_write;
-
-       if (PageChecked(page)) {
-               /*
-                * It's mmapped pagecache.  Add buffers and journal it.  There
-                * doesn't seem much point in redirtying the page here.
-                */
-               ClearPageChecked(page);
-               return __ext4_journalled_writepage(page, wbc);
-       } else {
-               /*
-                * It may be a page full of checkpoint-mode buffers.  We don't
-                * really know unless we go poke around in the buffer_heads.
-                * But block_write_full_page will do the right thing.
-                */
-               return block_write_full_page(page, noalloc_get_block_write,
-                                            wbc);
-       }
-no_write:
-       redirty_page_for_writepage(wbc, page);
-       unlock_page(page);
-       return 0;
-}
-
 static int ext4_readpage(struct file *file, struct page *page)
 {
        return mpage_readpage(page, ext4_get_block);
@@ -3492,7 +3363,7 @@ static int ext4_journalled_set_page_dirty(struct page *page)
 static const struct address_space_operations ext4_ordered_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_normal_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_ordered_write_end,
@@ -3507,7 +3378,7 @@ static const struct address_space_operations ext4_ordered_aops = {
 static const struct address_space_operations ext4_writeback_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_normal_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_writeback_write_end,
@@ -3522,7 +3393,7 @@ static const struct address_space_operations ext4_writeback_aops = {
 static const struct address_space_operations ext4_journalled_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_journalled_writepage,
+       .writepage              = ext4_writepage,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_journalled_write_end,
@@ -3536,7 +3407,7 @@ static const struct address_space_operations ext4_journalled_aops = {
 static const struct address_space_operations ext4_da_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
-       .writepage              = ext4_da_writepage,
+       .writepage              = ext4_writepage,
        .writepages             = ext4_da_writepages,
        .sync_page              = block_sync_page,
        .write_begin            = ext4_da_write_begin,
@@ -3583,7 +3454,8 @@ int ext4_block_truncate_page(handle_t *handle,
        struct page *page;
        int err = 0;
 
-       page = grab_cache_page(mapping, from >> PAGE_CACHE_SHIFT);
+       page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT,
+                                  mapping_gfp_mask(mapping) & ~__GFP_FS);
        if (!page)
                return -EINVAL;
 
index bb415408fdb60cc18243b70c4eec8ea9d82a67ed..7050a9cd04a4361bb66851781b9e494893f257ee 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/capability.h>
 #include <linux/time.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/mount.h>
 #include <linux/file.h>
 #include <asm/uaccess.h>
@@ -192,7 +191,7 @@ setversion_out:
        case EXT4_IOC_GROUP_EXTEND: {
                ext4_fsblk_t n_blocks_count;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -205,9 +204,11 @@ setversion_out:
                        return err;
 
                err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
@@ -252,7 +253,7 @@ setversion_out:
        case EXT4_IOC_GROUP_ADD: {
                struct ext4_new_group_data input;
                struct super_block *sb = inode->i_sb;
-               int err, err2;
+               int err, err2=0;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -266,9 +267,11 @@ setversion_out:
                        return err;
 
                err = ext4_group_add(sb, &input);
-               jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
-               jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
index 519a0a686d946343ca646702aa5c4603c9a75308..cd258463e2a9e017f949367b403d87332e5a3d24 100644 (file)
@@ -657,7 +657,8 @@ static void ext4_mb_mark_free_simple(struct super_block *sb,
        }
 }
 
-static void ext4_mb_generate_buddy(struct super_block *sb,
+static noinline_for_stack
+void ext4_mb_generate_buddy(struct super_block *sb,
                                void *buddy, void *bitmap, ext4_group_t group)
 {
        struct ext4_group_info *grp = ext4_get_group_info(sb, group);
@@ -1480,7 +1481,8 @@ static void ext4_mb_measure_extent(struct ext4_allocation_context *ac,
        ext4_mb_check_limits(ac, e4b, 0);
 }
 
-static int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
+static noinline_for_stack
+int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct ext4_free_extent ex = ac->ac_b_ex;
@@ -1507,7 +1509,8 @@ static int ext4_mb_try_best_found(struct ext4_allocation_context *ac,
        return 0;
 }
 
-static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
+static noinline_for_stack
+int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
                                struct ext4_buddy *e4b)
 {
        ext4_group_t group = ac->ac_g_ex.fe_group;
@@ -1566,7 +1569,8 @@ static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
  * The routine scans buddy structures (not bitmap!) from given order
  * to max order and tries to find big enough chunk to satisfy the req
  */
-static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1609,7 +1613,8 @@ static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
  * In order to optimize scanning, caller must pass number of
  * free blocks in the group, so the routine can know upper limit.
  */
-static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1668,7 +1673,8 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
  * we try to find stripe-aligned chunks for stripe-size requests
  * XXX should do so at least for multiples of stripe size as well
  */
-static void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
+static noinline_for_stack
+void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
                                 struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
@@ -1831,7 +1837,8 @@ void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
 
 }
 
-static int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
+static noinline_for_stack
+int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
 {
 
        int ret;
@@ -2902,7 +2909,11 @@ int __init init_ext4_mballoc(void)
 
 void exit_ext4_mballoc(void)
 {
-       /* XXX: synchronize_rcu(); */
+       /* 
+        * Wait for completion of call_rcu()'s on ext4_pspace_cachep
+        * before destroying the slab cache.
+        */
+       rcu_barrier();
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
        kmem_cache_destroy(ext4_free_ext_cachep);
@@ -3457,7 +3468,8 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
  * used in in-core bitmap. buddy must be generated from this bitmap
  * Need to be called with ext4 group lock held
  */
-static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
+static noinline_for_stack
+void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group)
 {
        struct ext4_group_info *grp = ext4_get_group_info(sb, group);
@@ -4215,14 +4227,9 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ext4_get_group_no_and_offset(sb, goal, &group, &block);
 
        /* set up allocation goals */
+       memset(ac, 0, sizeof(struct ext4_allocation_context));
        ac->ac_b_ex.fe_logical = ar->logical;
-       ac->ac_b_ex.fe_group = 0;
-       ac->ac_b_ex.fe_start = 0;
-       ac->ac_b_ex.fe_len = 0;
        ac->ac_status = AC_STATUS_CONTINUE;
-       ac->ac_groups_scanned = 0;
-       ac->ac_ex_scanned = 0;
-       ac->ac_found = 0;
        ac->ac_sb = sb;
        ac->ac_inode = ar->inode;
        ac->ac_o_ex.fe_logical = ar->logical;
@@ -4233,15 +4240,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ac->ac_g_ex.fe_group = group;
        ac->ac_g_ex.fe_start = block;
        ac->ac_g_ex.fe_len = len;
-       ac->ac_f_ex.fe_len = 0;
        ac->ac_flags = ar->flags;
-       ac->ac_2order = 0;
-       ac->ac_criteria = 0;
-       ac->ac_pa = NULL;
-       ac->ac_bitmap_page = NULL;
-       ac->ac_buddy_page = NULL;
-       ac->alloc_semp = NULL;
-       ac->ac_lg = NULL;
 
        /* we have to define context: we'll we work with a file or
         * locality group. this is a policy, actually */
@@ -4509,10 +4508,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        }
 
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
-       if (ac) {
-               ac->ac_sb = sb;
-               ac->ac_inode = ar->inode;
-       } else {
+       if (!ac) {
                ar->len = 0;
                *errp = -ENOMEM;
                goto out1;
index 38ff75a0fe22d3b8764e9be001dd57857c5abe66..530b4ca0151037ae212fe9d2d8ffb827fc970f98 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/compat.h>
 #include <asm/uaccess.h>
index b28ea646ff607cfdbe0f1ebda29158b5feadef88..f042b965c95c8a9c6c0dbb21020877372b1a9c21 100644 (file)
@@ -134,7 +134,7 @@ static int fat_file_release(struct inode *inode, struct file *filp)
        if ((filp->f_mode & FMODE_WRITE) &&
             MSDOS_SB(inode->i_sb)->options.flush) {
                fat_flush_inodes(inode->i_sb, inode, NULL);
-               congestion_wait(WRITE, HZ/10);
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
        return 0;
 }
index 82f88733b681accfa68bdeb86bed85734b9fcc6e..bbc94ae4fd77150203435058b79e46a03bfb40bc 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include "fat.h"
 
 /* Characters that are undesirable in an MS-DOS file name */
index 73471b7ecc8c2bd90591f43391afaaeacf6c39af..cb6e83557112d74e03cf00f37d6b3bddfa66cd83 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/jiffies.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/namei.h>
 #include "fat.h"
index a040b764f8e38b6a5067642713d4f9c6e9dc92ba..ae413086db978093123b2a59947d78e23a02a693 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/signal.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
-#include <linux/smp_lock.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
index cdbd1654e4cde4b6dd6b62e7bb6f2bd4a128a42c..1e8af939b3e4ad58d41726db3851269193a2e0c9 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/stat.h>
 #include <linux/vfs.h>
 #include <linux/mount.h>
index f58ecbc416c86043262013a3276af2927862ec11..6484eb75acd6f318c04238a51763b7cf2c9599ea 100644 (file)
@@ -286,8 +286,8 @@ __releases(&fc->lock)
                }
                if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
                    fc->connected && fc->bdi_initialized) {
-                       clear_bdi_congested(&fc->bdi, READ);
-                       clear_bdi_congested(&fc->bdi, WRITE);
+                       clear_bdi_congested(&fc->bdi, BLK_RW_SYNC);
+                       clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
                }
                fc->num_background--;
                fc->active_background--;
@@ -414,8 +414,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
                fc->blocked = 1;
        if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
            fc->bdi_initialized) {
-               set_bdi_congested(&fc->bdi, READ);
-               set_bdi_congested(&fc->bdi, WRITE);
+               set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
+               set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
        }
        list_add_tail(&req->list, &fc->bg_queue);
        flush_bg_queue(fc);
index 98d6ef1c1dc067eba8a780fca4c5dac84dd1d379..148d55c14171dee39435c83d56c906c09dcd0cf8 100644 (file)
@@ -1,12 +1,11 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gfs2
+
 #if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_GFS2_H
 
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM gfs2
-#define TRACE_INCLUDE_FILE trace_gfs2
-
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/dlmconstants.h>
@@ -403,5 +402,6 @@ TRACE_EVENT(gfs2_block_alloc,
 /* This part must be outside protection */
 #undef TRACE_INCLUDE_PATH
 #define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_gfs2
 #include <trace/define_trace.h>
 
index 6f833dc8e91022411939a290988af8a36e8d2018..f7fcbe49da723c40b56c816c8f04bea6e8d24616 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/nls.h>
 #include <linux/parser.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 
 #include "hfs_fs.h"
index 9fc3af0c0dab6cd5b58af0f8a0cb0d0019ed9011..c0759fe0855b623863eac1345c8b8e4bf35608a9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/nls.h>
 
index 6916c41d70176f97dd22326dd7d47d4a39abfdeb..8865c94f55f602f19cb3b68182fc70bd41fcb4e4 100644 (file)
@@ -6,6 +6,7 @@
  *  directory VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 static int hpfs_dir_release(struct inode *inode, struct file *filp)
index 64ab52259204b24f20aa356d60ab73b1df982346..3efabff00367672a5a7bb722984590c14346338a 100644 (file)
@@ -6,6 +6,7 @@
  *  file VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 #define BLOCKS(size) (((size) + 511) >> 9)
index c2ea31bae313092dff76107889b79596cf7b417a..701ca54c0867fe482b9c33fdb6615a015114fa95 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include "hpfs.h"
 
index 39a1bfbea3122ed430fdffcd38f5aab02d62b68f..fe703ae46bc773f95a8502f12ccae915531d4271 100644 (file)
@@ -6,6 +6,7 @@
  *  inode VFS functions
  */
 
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 void hpfs_init_inode(struct inode *i)
index b649232dde97baf4eac591548b7944c5aedcc666..82b9c4ba9ed08b07eda6832d6a5953581f515967 100644 (file)
@@ -6,6 +6,7 @@
  *  adding & removing files & directories
  */
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include "hpfs_fn.h"
 
 static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
index 58a7963e168ae4b8b4486fa54cd4b5fb5d66a9ee..85f96bc651c727ba04915138c50b45e9b63a3acd 100644 (file)
@@ -142,6 +142,7 @@ static const struct dentry_operations isofs_dentry_ops[] = {
 
 struct iso9660_options{
        unsigned int rock:1;
+       unsigned int joliet:1;
        unsigned int cruft:1;
        unsigned int hide:1;
        unsigned int showassoc:1;
@@ -151,7 +152,6 @@ struct iso9660_options{
        unsigned int gid_set:1;
        unsigned int utf8:1;
        unsigned char map;
-       char joliet;
        unsigned char check;
        unsigned int blocksize;
        mode_t fmode;
@@ -632,7 +632,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
                        else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
                                sec = (struct iso_supplementary_descriptor *)vdp;
                                if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
-                                       if (opt.joliet == 'y') {
+                                       if (opt.joliet) {
                                                if (sec->escape[2] == 0x40)
                                                        joliet_level = 1;
                                                else if (sec->escape[2] == 0x43)
index 737f7246a4b5ddc750b4a5198928f4b5afacc193..f96f85092d1cf2bffb671d147470666118b4bc7d 100644 (file)
@@ -287,6 +287,7 @@ int journal_write_metadata_buffer(transaction_t *transaction,
        struct page *new_page;
        unsigned int new_offset;
        struct buffer_head *bh_in = jh2bh(jh_in);
+       journal_t *journal = transaction->t_journal;
 
        /*
         * The buffer really shouldn't be locked: only the current committing
@@ -300,6 +301,11 @@ int journal_write_metadata_buffer(transaction_t *transaction,
        J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
 
        new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+       /* keep subsequent assertions sane */
+       new_bh->b_state = 0;
+       init_buffer(new_bh, NULL, NULL);
+       atomic_set(&new_bh->b_count, 1);
+       new_jh = journal_add_journal_head(new_bh);      /* This sleeps */
 
        /*
         * If a new transaction has already done a buffer copy-out, then
@@ -361,14 +367,6 @@ repeat:
                kunmap_atomic(mapped_data, KM_USER0);
        }
 
-       /* keep subsequent assertions sane */
-       new_bh->b_state = 0;
-       init_buffer(new_bh, NULL, NULL);
-       atomic_set(&new_bh->b_count, 1);
-       jbd_unlock_bh_state(bh_in);
-
-       new_jh = journal_add_journal_head(new_bh);      /* This sleeps */
-
        set_bh_page(new_bh, new_page, new_offset);
        new_jh->b_transaction = NULL;
        new_bh->b_size = jh2bh(jh_in)->b_size;
@@ -385,7 +383,11 @@ repeat:
         * copying is moved to the transaction's shadow queue.
         */
        JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
-       journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_lock(&journal->j_list_lock);
+       __journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_unlock(&journal->j_list_lock);
+       jbd_unlock_bh_state(bh_in);
+
        JBUFFER_TRACE(new_jh, "file as BJ_IO");
        journal_file_buffer(new_jh, transaction, BJ_IO);
 
@@ -848,6 +850,12 @@ static int journal_reset(journal_t *journal)
 
        first = be32_to_cpu(sb->s_first);
        last = be32_to_cpu(sb->s_maxlen);
+       if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) {
+               printk(KERN_ERR "JBD: Journal too short (blocks %lu-%lu).\n",
+                      first, last);
+               journal_fail_superblock(journal);
+               return -EINVAL;
+       }
 
        journal->j_first = first;
        journal->j_last = last;
index 73242ba7c7b1315d9cea08de1f85f1189293dd22..c03ac11f74be1313b8f7d09a24eba88f1d27ceed 100644 (file)
@@ -489,34 +489,15 @@ void journal_unlock_updates (journal_t *journal)
        wake_up(&journal->j_wait_transaction_locked);
 }
 
-/*
- * Report any unexpected dirty buffers which turn up.  Normally those
- * indicate an error, but they can occur if the user is running (say)
- * tune2fs to modify the live filesystem, so we need the option of
- * continuing as gracefully as possible.  #
- *
- * The caller should already hold the journal lock and
- * j_list_lock spinlock: most callers will need those anyway
- * in order to probe the buffer's journaling state safely.
- */
-static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+static void warn_dirty_buffer(struct buffer_head *bh)
 {
-       int jlist;
-
-       /* If this buffer is one which might reasonably be dirty
-        * --- ie. data, or not part of this journal --- then
-        * we're OK to leave it alone, but otherwise we need to
-        * move the dirty bit to the journal's own internal
-        * JBDDirty bit. */
-       jlist = jh->b_jlist;
+       char b[BDEVNAME_SIZE];
 
-       if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
-           jlist == BJ_Shadow || jlist == BJ_Forget) {
-               struct buffer_head *bh = jh2bh(jh);
-
-               if (test_clear_buffer_dirty(bh))
-                       set_buffer_jbddirty(bh);
-       }
+       printk(KERN_WARNING
+              "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+              "There's a risk of filesystem corruption in case of system "
+              "crash.\n",
+              bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
 }
 
 /*
@@ -583,14 +564,16 @@ repeat:
                        if (jh->b_next_transaction)
                                J_ASSERT_JH(jh, jh->b_next_transaction ==
                                                        transaction);
+                       warn_dirty_buffer(bh);
                }
                /*
                 * In any case we need to clean the dirty flag and we must
                 * do it under the buffer lock to be sure we don't race
                 * with running write-out.
                 */
-               JBUFFER_TRACE(jh, "Unexpected dirty buffer");
-               jbd_unexpected_dirty_buffer(jh);
+               JBUFFER_TRACE(jh, "Journalling dirty buffer");
+               clear_buffer_dirty(bh);
+               set_buffer_jbddirty(bh);
        }
 
        unlock_buffer(bh);
@@ -826,6 +809,15 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
        J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
 
        if (jh->b_transaction == NULL) {
+               /*
+                * Previous journal_forget() could have left the buffer
+                * with jbddirty bit set because it was being committed. When
+                * the commit finished, we've filed the buffer for
+                * checkpointing and marked it dirty. Now we are reallocating
+                * the buffer so the transaction freeing it must have
+                * committed and so it's safe to clear the dirty bit.
+                */
+               clear_buffer_dirty(jh2bh(jh));
                jh->b_transaction = transaction;
 
                /* first access by this transaction */
@@ -1782,8 +1774,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
 
        if (jh->b_cp_transaction) {
                JBUFFER_TRACE(jh, "on running+cp transaction");
+               /*
+                * We don't want to write the buffer anymore, clear the
+                * bit so that we don't confuse checks in
+                * __journal_file_buffer
+                */
+               clear_buffer_dirty(bh);
                __journal_file_buffer(jh, transaction, BJ_Forget);
-               clear_buffer_jbddirty(bh);
                may_free = 0;
        } else {
                JBUFFER_TRACE(jh, "on running transaction");
@@ -2041,12 +2038,17 @@ void __journal_file_buffer(struct journal_head *jh,
        if (jh->b_transaction && jh->b_jlist == jlist)
                return;
 
-       /* The following list of buffer states needs to be consistent
-        * with __jbd_unexpected_dirty_buffer()'s handling of dirty
-        * state. */
-
        if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
            jlist == BJ_Shadow || jlist == BJ_Forget) {
+               /*
+                * For metadata buffers, we track dirty bit in buffer_jbddirty
+                * instead of buffer_dirty. We should not see a dirty bit set
+                * here because we clear it in do_get_write_access but e.g.
+                * tune2fs can modify the sb and set the dirty bit at any time
+                * so we try to gracefully handle that.
+                */
+               if (buffer_dirty(bh))
+                       warn_dirty_buffer(bh);
                if (test_clear_buffer_dirty(bh) ||
                    test_clear_buffer_jbddirty(bh))
                        was_dirty = 1;
index 18bfd5dab64220d7d11fc90b6efb7c79e807c16a..e378cb383979a3e8e54234b14aa354e890c54e26 100644 (file)
@@ -297,6 +297,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
        unsigned int new_offset;
        struct buffer_head *bh_in = jh2bh(jh_in);
        struct jbd2_buffer_trigger_type *triggers;
+       journal_t *journal = transaction->t_journal;
 
        /*
         * The buffer really shouldn't be locked: only the current committing
@@ -310,6 +311,11 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
        J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
 
        new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+       /* keep subsequent assertions sane */
+       new_bh->b_state = 0;
+       init_buffer(new_bh, NULL, NULL);
+       atomic_set(&new_bh->b_count, 1);
+       new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
 
        /*
         * If a new transaction has already done a buffer copy-out, then
@@ -388,14 +394,6 @@ repeat:
                kunmap_atomic(mapped_data, KM_USER0);
        }
 
-       /* keep subsequent assertions sane */
-       new_bh->b_state = 0;
-       init_buffer(new_bh, NULL, NULL);
-       atomic_set(&new_bh->b_count, 1);
-       jbd_unlock_bh_state(bh_in);
-
-       new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
-
        set_bh_page(new_bh, new_page, new_offset);
        new_jh->b_transaction = NULL;
        new_bh->b_size = jh2bh(jh_in)->b_size;
@@ -412,7 +410,11 @@ repeat:
         * copying is moved to the transaction's shadow queue.
         */
        JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
-       jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_lock(&journal->j_list_lock);
+       __jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
+       spin_unlock(&journal->j_list_lock);
+       jbd_unlock_bh_state(bh_in);
+
        JBUFFER_TRACE(new_jh, "file as BJ_IO");
        jbd2_journal_file_buffer(new_jh, transaction, BJ_IO);
 
@@ -2410,6 +2412,7 @@ const char *jbd2_dev_to_name(dev_t device)
        int     i = hash_32(device, CACHE_SIZE_BITS);
        char    *ret;
        struct block_device *bd;
+       static struct devname_cache *new_dev;
 
        rcu_read_lock();
        if (devcache[i] && devcache[i]->device == device) {
@@ -2419,20 +2422,20 @@ const char *jbd2_dev_to_name(dev_t device)
        }
        rcu_read_unlock();
 
+       new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
+       if (!new_dev)
+               return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
        spin_lock(&devname_cache_lock);
        if (devcache[i]) {
                if (devcache[i]->device == device) {
+                       kfree(new_dev);
                        ret = devcache[i]->devname;
                        spin_unlock(&devname_cache_lock);
                        return ret;
                }
                call_rcu(&devcache[i]->rcu, free_devcache);
        }
-       devcache[i] = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
-       if (!devcache[i]) {
-               spin_unlock(&devname_cache_lock);
-               return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
-       }
+       devcache[i] = new_dev;
        devcache[i]->device = device;
        bd = bdget(device);
        if (bd) {
index 494501edba6bcf0ce39c129848d5862177e1d38b..6213ac728f303286e15a2b6703fc90d69e2bd6ba 100644 (file)
@@ -499,34 +499,15 @@ void jbd2_journal_unlock_updates (journal_t *journal)
        wake_up(&journal->j_wait_transaction_locked);
 }
 
-/*
- * Report any unexpected dirty buffers which turn up.  Normally those
- * indicate an error, but they can occur if the user is running (say)
- * tune2fs to modify the live filesystem, so we need the option of
- * continuing as gracefully as possible.  #
- *
- * The caller should already hold the journal lock and
- * j_list_lock spinlock: most callers will need those anyway
- * in order to probe the buffer's journaling state safely.
- */
-static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+static void warn_dirty_buffer(struct buffer_head *bh)
 {
-       int jlist;
-
-       /* If this buffer is one which might reasonably be dirty
-        * --- ie. data, or not part of this journal --- then
-        * we're OK to leave it alone, but otherwise we need to
-        * move the dirty bit to the journal's own internal
-        * JBDDirty bit. */
-       jlist = jh->b_jlist;
+       char b[BDEVNAME_SIZE];
 
-       if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
-           jlist == BJ_Shadow || jlist == BJ_Forget) {
-               struct buffer_head *bh = jh2bh(jh);
-
-               if (test_clear_buffer_dirty(bh))
-                       set_buffer_jbddirty(bh);
-       }
+       printk(KERN_WARNING
+              "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+              "There's a risk of filesystem corruption in case of system "
+              "crash.\n",
+              bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
 }
 
 /*
@@ -593,14 +574,16 @@ repeat:
                        if (jh->b_next_transaction)
                                J_ASSERT_JH(jh, jh->b_next_transaction ==
                                                        transaction);
+                       warn_dirty_buffer(bh);
                }
                /*
                 * In any case we need to clean the dirty flag and we must
                 * do it under the buffer lock to be sure we don't race
                 * with running write-out.
                 */
-               JBUFFER_TRACE(jh, "Unexpected dirty buffer");
-               jbd_unexpected_dirty_buffer(jh);
+               JBUFFER_TRACE(jh, "Journalling dirty buffer");
+               clear_buffer_dirty(bh);
+               set_buffer_jbddirty(bh);
        }
 
        unlock_buffer(bh);
@@ -843,6 +826,15 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
        J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
 
        if (jh->b_transaction == NULL) {
+               /*
+                * Previous jbd2_journal_forget() could have left the buffer
+                * with jbddirty bit set because it was being committed. When
+                * the commit finished, we've filed the buffer for
+                * checkpointing and marked it dirty. Now we are reallocating
+                * the buffer so the transaction freeing it must have
+                * committed and so it's safe to clear the dirty bit.
+                */
+               clear_buffer_dirty(jh2bh(jh));
                jh->b_transaction = transaction;
 
                /* first access by this transaction */
@@ -1644,8 +1636,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
 
        if (jh->b_cp_transaction) {
                JBUFFER_TRACE(jh, "on running+cp transaction");
+               /*
+                * We don't want to write the buffer anymore, clear the
+                * bit so that we don't confuse checks in
+                * __journal_file_buffer
+                */
+               clear_buffer_dirty(bh);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
-               clear_buffer_jbddirty(bh);
                may_free = 0;
        } else {
                JBUFFER_TRACE(jh, "on running transaction");
@@ -1896,12 +1893,17 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
        if (jh->b_transaction && jh->b_jlist == jlist)
                return;
 
-       /* The following list of buffer states needs to be consistent
-        * with __jbd_unexpected_dirty_buffer()'s handling of dirty
-        * state. */
-
        if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
            jlist == BJ_Shadow || jlist == BJ_Forget) {
+               /*
+                * For metadata buffers, we track dirty bit in buffer_jbddirty
+                * instead of buffer_dirty. We should not see a dirty bit set
+                * here because we clear it in do_get_write_access but e.g.
+                * tune2fs can modify the sb and set the dirty bit at any time
+                * so we try to gracefully handle that.
+                */
+               if (buffer_dirty(bh))
+                       warn_dirty_buffer(bh);
                if (test_clear_buffer_dirty(bh) ||
                    test_clear_buffer_jbddirty(bh))
                        was_dirty = 1;
index 07a22caf26878223efffacdb01c69e23d4ce7a47..0035c021395ac840cd71bd38c82f28b4ad154f19 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/fs.h>
index 91fa3ad6e8c2dc01144bcf1ab56c250a9c9e54bb..a29c7c3e3fb81a58148c93e0dd56e858bac04939 100644 (file)
@@ -67,10 +67,8 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
                acl = posix_acl_from_xattr(value, size);
        }
        kfree(value);
-       if (!IS_ERR(acl)) {
+       if (!IS_ERR(acl))
                set_cached_acl(inode, type, acl);
-               posix_acl_release(acl);
-       }
        return acl;
 }
 
index f2fdcbce143efa9bb43ed363301674e0db179294..4336adba952a770343150468053a866fe49016c7 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
index 1725037374c595e3919f2cbb566f33593fd388f1..bd173a6ca3b1b0723b29d796ca77d6883f4fd25f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/in.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
index 3688e55901fc48e733c24329d05e140252004648..e1d28ddd21699060a8b1e0907a8806bea9e62f95 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/in.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
index c2d061675d80724ecf1f3ae45b467f7286cf28db..8d25ccb2d51d514a27a5098cfd13ad872cb46dc8 100644 (file)
@@ -1242,20 +1242,6 @@ error:
        return error;
 }
 
-/*
- * Initialize a session.
- * Note: save the mount rsize and wsize for create_server negotiation.
- */
-static void nfs4_init_session(struct nfs_client *clp,
-                             unsigned int wsize, unsigned int rsize)
-{
-#if defined(CONFIG_NFS_V4_1)
-       if (nfs4_has_session(clp)) {
-               clp->cl_session->fc_attrs.max_rqst_sz = wsize;
-               clp->cl_session->fc_attrs.max_resp_sz = rsize;
-       }
-#endif /* CONFIG_NFS_V4_1 */
-}
 
 /*
  * Session has been established, and the client marked ready.
@@ -1350,7 +1336,9 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
        BUG_ON(!server->nfs_client->rpc_ops);
        BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
 
-       nfs4_init_session(server->nfs_client, server->wsize, server->rsize);
+       error = nfs4_init_session(server);
+       if (error < 0)
+               goto error;
 
        /* Probe the root fh to retrieve its FSID */
        error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path);
index af05b918cb5bcce6655aee1d16adaf9000fe9d25..6dd48a4405b46d409af629d4195b27b17e83dab1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
 #include <linux/nfs4.h>
index 89f98e9a024b73accbfce55d575834e9357be491..32062c33c859496198395db435117c7c33105d3d 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/pagevec.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
@@ -1026,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
                                res = NULL;
                                goto out;
                        /* This turned out not to be a regular file */
-                       case -EISDIR:
                        case -ENOTDIR:
                                goto no_open;
                        case -ELOOP:
                                if (!(nd->intent.open.flags & O_NOFOLLOW))
                                        goto no_open;
+                       /* case -EISDIR: */
                        /* case -EINVAL: */
                        default:
                                goto out;
index 0055b813ec2c7004e9647ad781c3706066aeac3e..05062329b678a148c464990b0f9d4f6a68ab617f 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/aio.h>
 
 #include <asm/uaccess.h>
index 64f87194d3907620709c5413f23c95324b23afd9..bd7938eda6a8258a6e3ced41f495b78ab57afb3d 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
 #include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include <linux/nfs_idmap.h>
index 61bc3a32e1e25780c4b9aa896814e22945fc2842..6ea07a3c75d4942f6197e54791b7504502d3f54c 100644 (file)
@@ -220,6 +220,7 @@ extern void nfs4_destroy_session(struct nfs4_session *session);
 extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 extern int nfs4_proc_create_session(struct nfs_client *, int reset);
 extern int nfs4_proc_destroy_session(struct nfs4_session *);
+extern int nfs4_init_session(struct nfs_server *server);
 #else /* CONFIG_NFS_v4_1 */
 static inline int nfs4_setup_sequence(struct nfs_client *clp,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
@@ -227,6 +228,11 @@ static inline int nfs4_setup_sequence(struct nfs_client *clp,
 {
        return 0;
 }
+
+static inline int nfs4_init_session(struct nfs_server *server)
+{
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[];
index 92ce4351781459e648958e58c0cf59d106b3bc5c..6917311f201c32d679772337e440ba21e807a04b 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/module.h>
@@ -2041,15 +2040,9 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       int status;
 
        nfs_fattr_init(info->fattr);
-       status = nfs4_recover_expired_lease(server);
-       if (!status)
-               status = nfs4_check_client_ready(server->nfs_client);
-       if (!status)
-               status = nfs4_call_sync(server, &msg, &args, &res, 0);
-       return status;
+       return nfs4_call_sync(server, &msg, &args, &res, 0);
 }
 
 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -4100,15 +4093,23 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
        if (request->fl_start < 0 || request->fl_end < 0)
                return -EINVAL;
 
-       if (IS_GETLK(cmd))
-               return nfs4_proc_getlk(state, F_GETLK, request);
+       if (IS_GETLK(cmd)) {
+               if (state != NULL)
+                       return nfs4_proc_getlk(state, F_GETLK, request);
+               return 0;
+       }
 
        if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
                return -EINVAL;
 
-       if (request->fl_type == F_UNLCK)
-               return nfs4_proc_unlck(state, cmd, request);
+       if (request->fl_type == F_UNLCK) {
+               if (state != NULL)
+                       return nfs4_proc_unlck(state, cmd, request);
+               return 0;
+       }
 
+       if (state == NULL)
+               return -ENOLCK;
        do {
                status = nfs4_proc_setlk(state, cmd, request);
                if ((status != -EAGAIN) || IS_SETLK(cmd))
@@ -4794,6 +4795,22 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
        return status;
 }
 
+int nfs4_init_session(struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       int ret;
+
+       if (!nfs4_has_session(clp))
+               return 0;
+
+       clp->cl_session->fc_attrs.max_rqst_sz = server->wsize;
+       clp->cl_session->fc_attrs.max_resp_sz = server->rsize;
+       ret = nfs4_recover_expired_lease(server);
+       if (!ret)
+               ret = nfs4_check_client_ready(clp);
+       return ret;
+}
+
 /*
  * Renew the cl_session lease.
  */
index b73c5a728655adef0a90751b18133c75895aac0c..65ca8c18476fb3d1e437fed82685f50d824a92c5 100644 (file)
@@ -553,6 +553,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
        INIT_LIST_HEAD(&lsp->ls_sequence.list);
        lsp->ls_seqid.sequence = &lsp->ls_sequence;
        atomic_set(&lsp->ls_count, 1);
+       lsp->ls_state = state;
        lsp->ls_owner = fl_owner;
        spin_lock(&clp->cl_lock);
        nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
@@ -587,7 +588,6 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
                if (lsp != NULL)
                        break;
                if (new != NULL) {
-                       new->ls_state = state;
                        list_add(&new->ls_locks, &state->lock_states);
                        set_bit(LK_STATE_IN_USE, &state->flags);
                        lsp = new;
index 96c4ebfa46f4f8892b125fcf59bdb300cc2f01ad..73ea5e8d66ceebbfab4079c4ab91b62809093ed7 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 
index ce728829f79a5dce2b238ccbe763631adec71343..0a0a2ff767c318d5924c603a3f67ed7f5ccc9402 100644 (file)
@@ -202,8 +202,10 @@ static int nfs_set_page_writeback(struct page *page)
                struct nfs_server *nfss = NFS_SERVER(inode);
 
                if (atomic_long_inc_return(&nfss->writeback) >
-                               NFS_CONGESTION_ON_THRESH)
-                       set_bdi_congested(&nfss->backing_dev_info, WRITE);
+                               NFS_CONGESTION_ON_THRESH) {
+                       set_bdi_congested(&nfss->backing_dev_info,
+                                               BLK_RW_ASYNC);
+               }
        }
        return ret;
 }
@@ -215,7 +217,7 @@ static void nfs_end_page_writeback(struct page *page)
 
        end_page_writeback(page);
        if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
-               clear_bdi_congested(&nfss->backing_dev_info, WRITE);
+               clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
 }
 
 /*
index 1250fb978ac1451b8d00f87bfe5183eb12d9f26f..6d0847562d876374a6e5ba838651af37c00aad2d 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/inet.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/ctype.h>
 
 #include <linux/nfs.h>
index d4c9884cd54b2bf680cc2360eaa1a9f20dec8b55..492c79b7800b5b7fcb4f8a8813b2d369a5039d7a 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/freezer.h>
 #include <linux/fs_struct.h>
 #include <linux/kthread.h>
diff --git a/fs/nilfs2/Kconfig b/fs/nilfs2/Kconfig
new file mode 100644 (file)
index 0000000..72da095
--- /dev/null
@@ -0,0 +1,25 @@
+config NILFS2_FS
+       tristate "NILFS2 file system support (EXPERIMENTAL)"
+       depends on BLOCK && EXPERIMENTAL
+       select CRC32
+       help
+         NILFS2 is a log-structured file system (LFS) supporting continuous
+         snapshotting.  In addition to versioning capability of the entire
+         file system, users can even restore files mistakenly overwritten or
+         destroyed just a few seconds ago.  Since this file system can keep
+         consistency like conventional LFS, it achieves quick recovery after
+         system crashes.
+
+         NILFS2 creates a number of checkpoints every few seconds or per
+         synchronous write basis (unless there is no change).  Users can
+         select significant versions among continuously created checkpoints,
+         and can change them into snapshots which will be preserved for long
+         periods until they are changed back to checkpoints.  Each
+         snapshot is mountable as a read-only file system concurrently with
+         its writable mount, and this feature is convenient for online backup.
+
+         Some features including atime, extended attributes, and POSIX ACLs,
+         are not supported yet.
+
+         To compile this file system support as a module, choose M here: the
+         module will be called nilfs2.  If unsure, say N.
index 36df60b6d8a4b79e9fde8f0f58e3a76ee8d0a1f4..99d58a028b94c3c9698661bac527e14ed2812a72 100644 (file)
@@ -568,6 +568,7 @@ void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap,
 }
 
 static struct lock_class_key nilfs_bmap_dat_lock_key;
+static struct lock_class_key nilfs_bmap_mdt_lock_key;
 
 /**
  * nilfs_bmap_read - read a bmap from an inode
@@ -603,7 +604,11 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode)
                bmap->b_ptr_type = NILFS_BMAP_PTR_VS;
                bmap->b_last_allocated_key = 0;
                bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR;
+               lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
                break;
+       case NILFS_IFILE_INO:
+               lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
+               /* Fall through */
        default:
                bmap->b_ptr_type = NILFS_BMAP_PTR_VM;
                bmap->b_last_allocated_key = 0;
index 7d49813f66d6c157d95c9ec8f6568379fa71565c..aec942cf79e34cc35764d270e645fd3f24a29229 100644 (file)
@@ -307,7 +307,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
                if (ret < 0) {
                        if (ret != -ENOENT)
-                               goto out_header;
+                               break;
                        /* skip hole */
                        ret = 0;
                        continue;
@@ -340,7 +340,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                                        continue;
                                printk(KERN_ERR "%s: cannot delete block\n",
                                       __func__);
-                               goto out_header;
+                               break;
                        }
                }
 
@@ -358,7 +358,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                kunmap_atomic(kaddr, KM_USER0);
        }
 
- out_header:
        brelse(header_bh);
 
  out_sem:
index 0b2710e2d56547ac7aa36b6367e5ed6f36685c49..8927ca27e6f79cbd82db5028d5dfd002baa99bb0 100644 (file)
@@ -134,15 +134,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
                                             req->pr_entry_bh, kaddr);
        entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat));
-       if (entry->de_blocknr != cpu_to_le64(0) ||
-           entry->de_end != cpu_to_le64(NILFS_CNO_MAX)) {
-               printk(KERN_CRIT
-                      "%s: vbn = %llu, start = %llu, end = %llu, pbn = %llu\n",
-                      __func__, (unsigned long long)req->pr_entry_nr,
-                      (unsigned long long)le64_to_cpu(entry->de_start),
-                      (unsigned long long)le64_to_cpu(entry->de_end),
-                      (unsigned long long)le64_to_cpu(entry->de_blocknr));
-       }
        entry->de_blocknr = cpu_to_le64(blocknr);
        kunmap_atomic(kaddr, KM_USER0);
 
index 54100acc1102706ed6c39116b89f7fbaa6c72f02..1a4fa04cf071bd8a82ae9f21d079612e963b419b 100644 (file)
@@ -43,7 +43,6 @@
  */
 
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include "nilfs.h"
 #include "page.h"
 
index aa977549919ecd2d92d40ff3d3d4f17f207f4814..8b5e4778cf28bc780fcf516400ccc7a2e963c076 100644 (file)
@@ -1829,26 +1829,13 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci,
                err = nilfs_segbuf_write(segbuf, &wi);
 
                res = nilfs_segbuf_wait(segbuf, &wi);
-               err = unlikely(err) ? : res;
-               if (unlikely(err))
+               err = err ? : res;
+               if (err)
                        return err;
        }
        return 0;
 }
 
-static int nilfs_page_has_uncleared_buffer(struct page *page)
-{
-       struct buffer_head *head, *bh;
-
-       head = bh = page_buffers(page);
-       do {
-               if (buffer_dirty(bh) && !list_empty(&bh->b_assoc_buffers))
-                       return 1;
-               bh = bh->b_this_page;
-       } while (bh != head);
-       return 0;
-}
-
 static void __nilfs_end_page_io(struct page *page, int err)
 {
        if (!err) {
@@ -1872,12 +1859,11 @@ static void nilfs_end_page_io(struct page *page, int err)
        if (!page)
                return;
 
-       if (buffer_nilfs_node(page_buffers(page)) &&
-           nilfs_page_has_uncleared_buffer(page))
-               /* For b-tree node pages, this function may be called twice
-                  or more because they might be split in a segment.
-                  This check assures that cleanup has been done for all
-                  buffers in a split btnode page. */
+       if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page))
+               /*
+                * For b-tree node pages, this function may be called twice
+                * or more because they might be split in a segment.
+                */
                return;
 
        __nilfs_end_page_io(page, err);
@@ -1940,7 +1926,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci,
                        }
                        if (bh->b_page != fs_page) {
                                nilfs_end_page_io(fs_page, err);
-                               if (unlikely(fs_page == failed_page))
+                               if (fs_page && fs_page == failed_page)
                                        goto done;
                                fs_page = bh->b_page;
                        }
index 31dac7e3b0f10c9e5eff17eb815bdbdfb36b2dbf..dffbb0911d022cea33b599aecb336f481a2a8741 100644 (file)
@@ -1,15 +1,5 @@
 config FSNOTIFY
-       bool "Filesystem notification backend"
-       default y
-       ---help---
-          fsnotify is a backend for filesystem notification.  fsnotify does
-          not provide any userspace interface but does provide the basis
-          needed for other notification schemes such as dnotify, inotify,
-          and fanotify.
-
-          Say Y here to enable fsnotify suport.
-
-          If unsure, say Y.
+       def_bool n
 
 source "fs/notify/dnotify/Kconfig"
 source "fs/notify/inotify/Kconfig"
index 904ff8d5405a04e5fd2a3cb38e8089f66aa5d622..f9c1ca139d8f6d3f134b1068dfef46e6058b5115 100644 (file)
@@ -1,6 +1,6 @@
 config DNOTIFY
        bool "Dnotify support"
-       depends on FSNOTIFY
+       select FSNOTIFY
        default y
        help
          Dnotify is a directory-based per-fd file change notification system
index ec2f7bd76818411b7a64b2784e86abec2eb9611b..037e878e03fcac70005fd6da12f776c76d89b38f 100644 (file)
@@ -159,7 +159,9 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
                        if (!group->ops->should_send_event(group, to_tell, mask))
                                continue;
                        if (!event) {
-                               event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie);
+                               event = fsnotify_create_event(to_tell, mask, data,
+                                                             data_is, file_name, cookie,
+                                                             GFP_KERNEL);
                                /* shit, we OOM'd and now we can't tell, maybe
                                 * someday someone else will want to do something
                                 * here */
index 5356884289a155d8375ef8315c41cea50e64781e..3e56dbffe7294421e58c17184d98b817c867ac0e 100644 (file)
@@ -15,7 +15,7 @@ config INOTIFY
 
 config INOTIFY_USER
        bool "Inotify support for userspace"
-       depends on FSNOTIFY
+       select FSNOTIFY
        default y
        ---help---
          Say Y here to enable inotify support for userspace, including the
index ff27a2965844cbc20ea56279cc419ea1c584faf5..f30d9bbc2e1bf80f61d16eaa46efc09a5f1bc8d5 100644 (file)
@@ -57,7 +57,6 @@ int inotify_max_user_watches __read_mostly;
 
 static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
 struct kmem_cache *event_priv_cachep __read_mostly;
-static struct fsnotify_event *inotify_ignored_event;
 
 /*
  * When inotify registers a new group it increments this and uses that
@@ -365,6 +364,17 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
        return error;
 }
 
+static void inotify_remove_from_idr(struct fsnotify_group *group,
+                                   struct inotify_inode_mark_entry *ientry)
+{
+       struct idr *idr;
+
+       spin_lock(&group->inotify_data.idr_lock);
+       idr = &group->inotify_data.idr;
+       idr_remove(idr, ientry->wd);
+       spin_unlock(&group->inotify_data.idr_lock);
+       ientry->wd = -1;
+}
 /*
  * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the
  * internal reference help on the mark because it is in the idr.
@@ -373,13 +383,19 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
                                    struct fsnotify_group *group)
 {
        struct inotify_inode_mark_entry *ientry;
+       struct fsnotify_event *ignored_event;
        struct inotify_event_private_data *event_priv;
        struct fsnotify_event_private_data *fsn_event_priv;
-       struct idr *idr;
+
+       ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
+                                             FSNOTIFY_EVENT_NONE, NULL, 0,
+                                             GFP_NOFS);
+       if (!ignored_event)
+               return;
 
        ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
 
-       event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL);
+       event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
        if (unlikely(!event_priv))
                goto skip_send_ignore;
 
@@ -388,7 +404,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
        fsn_event_priv->group = group;
        event_priv->wd = ientry->wd;
 
-       fsnotify_add_notify_event(group, inotify_ignored_event, fsn_event_priv);
+       fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
 
        /* did the private data get added? */
        if (list_empty(&fsn_event_priv->event_list))
@@ -396,14 +412,16 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
 
 skip_send_ignore:
 
+       /* matches the reference taken when the event was created */
+       fsnotify_put_event(ignored_event);
+
        /* remove this entry from the idr */
-       spin_lock(&group->inotify_data.idr_lock);
-       idr = &group->inotify_data.idr;
-       idr_remove(idr, ientry->wd);
-       spin_unlock(&group->inotify_data.idr_lock);
+       inotify_remove_from_idr(group, ientry);
 
        /* removed from idr, drop that reference */
        fsnotify_put_mark(entry);
+
+       atomic_dec(&group->inotify_data.user->inotify_watches);
 }
 
 /* ding dong the mark is dead */
@@ -418,6 +436,7 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
 {
        struct fsnotify_mark_entry *entry = NULL;
        struct inotify_inode_mark_entry *ientry;
+       struct inotify_inode_mark_entry *tmp_ientry;
        int ret = 0;
        int add = (arg & IN_MASK_ADD);
        __u32 mask;
@@ -428,54 +447,66 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
        if (unlikely(!mask))
                return -EINVAL;
 
-       ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
-       if (unlikely(!ientry))
+       tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
+       if (unlikely(!tmp_ientry))
                return -ENOMEM;
        /* we set the mask at the end after attaching it */
-       fsnotify_init_mark(&ientry->fsn_entry, inotify_free_mark);
-       ientry->wd = 0;
+       fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
+       tmp_ientry->wd = -1;
 
 find_entry:
        spin_lock(&inode->i_lock);
        entry = fsnotify_find_mark_entry(group, inode);
        spin_unlock(&inode->i_lock);
        if (entry) {
-               kmem_cache_free(inotify_inode_mark_cachep, ientry);
                ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
        } else {
-               if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) {
-                       ret = -ENOSPC;
-                       goto out_err;
-               }
-
-               ret = fsnotify_add_mark(&ientry->fsn_entry, group, inode);
-               if (ret == -EEXIST)
-                       goto find_entry;
-               else if (ret)
+               ret = -ENOSPC;
+               if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
                        goto out_err;
-
-               entry = &ientry->fsn_entry;
 retry:
                ret = -ENOMEM;
                if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
                        goto out_err;
 
                spin_lock(&group->inotify_data.idr_lock);
-               /* if entry is added to the idr we keep the reference obtained
-                * through fsnotify_mark_add.  remember to drop this reference
-                * when entry is removed from idr */
-               ret = idr_get_new_above(&group->inotify_data.idr, entry,
-                                       ++group->inotify_data.last_wd,
-                                       &ientry->wd);
+               ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
+                                       group->inotify_data.last_wd,
+                                       &tmp_ientry->wd);
                spin_unlock(&group->inotify_data.idr_lock);
                if (ret) {
                        if (ret == -EAGAIN)
                                goto retry;
                        goto out_err;
                }
+
+               ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
+               if (ret) {
+                       inotify_remove_from_idr(group, tmp_ientry);
+                       if (ret == -EEXIST)
+                               goto find_entry;
+                       goto out_err;
+               }
+
+               /* tmp_ientry has been added to the inode, so we are all set up.
+                * now we just need to make sure tmp_ientry doesn't get freed and
+                * we need to set up entry and ientry so the generic code can
+                * do its thing. */
+               ientry = tmp_ientry;
+               entry = &ientry->fsn_entry;
+               tmp_ientry = NULL;
+
                atomic_inc(&group->inotify_data.user->inotify_watches);
+
+               /* update the idr hint */
+               group->inotify_data.last_wd = ientry->wd;
+
+               /* we put the mark on the idr, take a reference */
+               fsnotify_get_mark(entry);
        }
 
+       ret = ientry->wd;
+
        spin_lock(&entry->lock);
 
        old_mask = entry->mask;
@@ -506,14 +537,19 @@ retry:
                        fsnotify_recalc_group_mask(group);
        }
 
-       return ientry->wd;
+       /* this either matches fsnotify_find_mark_entry, or init_mark_entry
+        * depending on which path we took... */
+       fsnotify_put_mark(entry);
 
 out_err:
-       /* see this isn't supposed to happen, just kill the watch */
-       if (entry) {
-               fsnotify_destroy_mark_by_entry(entry);
-               fsnotify_put_mark(entry);
+       /* could be an error, could be that we found an existing mark */
+       if (tmp_ientry) {
+               /* on the idr but didn't make it on the inode */
+               if (tmp_ientry->wd != -1)
+                       inotify_remove_from_idr(group, tmp_ientry);
+               kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
        }
+
        return ret;
 }
 
@@ -721,9 +757,6 @@ static int __init inotify_user_setup(void)
 
        inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC);
        event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);
-       inotify_ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
-       if (!inotify_ignored_event)
-               panic("unable to allocate the inotify ignored event\n");
 
        inotify_max_queued_events = 16384;
        inotify_max_user_instances = 128;
index 959b73e756fd8f22219b80e8224fec7cadb3bace..521368574e97b5841ec90c52ae8b4215ddc36dd4 100644 (file)
@@ -136,18 +136,24 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
 {
        if ((old->mask == new->mask) &&
            (old->to_tell == new->to_tell) &&
-           (old->data_type == new->data_type)) {
+           (old->data_type == new->data_type) &&
+           (old->name_len == new->name_len)) {
                switch (old->data_type) {
                case (FSNOTIFY_EVENT_INODE):
-                       if (old->inode == new->inode)
+                       /* remember, after old was put on the wait_q we aren't
+                        * allowed to look at the inode any more, only thing
+                        * left to check was if the file_name is the same */
+                       if (old->name_len &&
+                           !strcmp(old->file_name, new->file_name))
                                return true;
                        break;
                case (FSNOTIFY_EVENT_PATH):
                        if ((old->path.mnt == new->path.mnt) &&
                            (old->path.dentry == new->path.dentry))
                                return true;
+                       break;
                case (FSNOTIFY_EVENT_NONE):
-                       return true;
+                       return false;
                };
        }
        return false;
@@ -339,18 +345,19 @@ static void initialize_event(struct fsnotify_event *event)
  * @name the filename, if available
  */
 struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
-                                            int data_type, const char *name, u32 cookie)
+                                            int data_type, const char *name, u32 cookie,
+                                            gfp_t gfp)
 {
        struct fsnotify_event *event;
 
-       event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+       event = kmem_cache_alloc(fsnotify_event_cachep, gfp);
        if (!event)
                return NULL;
 
        initialize_event(event);
 
        if (name) {
-               event->file_name = kstrdup(name, GFP_KERNEL);
+               event->file_name = kstrdup(name, gfp);
                if (!event->file_name) {
                        kmem_cache_free(fsnotify_event_cachep, event);
                        return NULL;
index 9fcd36dcc9a05920e5cc3f2d4d001d5bc8a82120..467b413bec21e7b407f45a2adba2002e72504e72 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <linux/fs.h>
 #include <linux/mount.h>
-#include <linux/smp_lock.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
index 1a9c7878f8649b1df14531f66aa247fd2587e2c8..ea4e6cb29e1394f709f834df066a7659e12b1d2e 100644 (file)
@@ -436,7 +436,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        rcu_assign_pointer(ptbl->part[partno], p);
 
        /* suppress uevent if the disk supresses it */
-       if (!dev_get_uevent_suppress(pdev))
+       if (!dev_get_uevent_suppress(ddev))
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
        return p;
index f7dd21ad85a61937666eddf0ccbff66e11e6c3fd..52c4151148383c2e9cd89f891e322241e110d3c1 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -68,8 +68,8 @@ void pipe_double_lock(struct pipe_inode_info *pipe1,
                pipe_lock_nested(pipe1, I_MUTEX_PARENT);
                pipe_lock_nested(pipe2, I_MUTEX_CHILD);
        } else {
-               pipe_lock_nested(pipe2, I_MUTEX_CHILD);
-               pipe_lock_nested(pipe1, I_MUTEX_PARENT);
+               pipe_lock_nested(pipe2, I_MUTEX_PARENT);
+               pipe_lock_nested(pipe1, I_MUTEX_CHILD);
        }
 }
 
index 77f5bb746bf073969140539752ee87dc8f4f0861..90622200b39c0622e0f159d423c929a036d76257 100644 (file)
@@ -997,7 +997,7 @@ static int reiserfs_async_progress_wait(struct super_block *s)
        DEFINE_WAIT(wait);
        struct reiserfs_journal *j = SB_JOURNAL(s);
        if (atomic_read(&j->j_async_throttle))
-               congestion_wait(WRITE, HZ / 10);
+               congestion_wait(BLK_RW_ASYNC, HZ / 10);
        return 0;
 }
 
index f3d47d8568482f3dd2b20077e296b40bc8a428f1..6925b835a43b6f2f94e8a4217180b2e8d1735ab7 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/reiserfs_acl.h>
 #include <asm/uaccess.h>
 #include <net/checksum.h>
-#include <linux/smp_lock.h>
 #include <linux/stat.h>
 #include <linux/quotaops.h>
 
index 3b52770f46ffdcfbd4c6187a6dfd928f6135203c..cb5fc57e370be3babf4de90514fa89c2656f99f3 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/vfs.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
index d88d0fac9fa5f185afd13b1f36b11f58baec672d..14f2d71ea3ce8b7077b0da8774bc554b912cd0fb 100644 (file)
@@ -939,8 +939,10 @@ again:
        /* Remove from old parent's list and insert into new parent's list. */
        sysfs_unlink_sibling(sd);
        sysfs_get(new_parent_sd);
+       drop_nlink(old_parent->d_inode);
        sysfs_put(sd->s_parent);
        sd->s_parent = new_parent_sd;
+       inc_nlink(new_parent->d_inode);
        sysfs_link_sibling(sd);
 
  out_unlock:
index bc5857199ec2a021c1f9f9838b11329461704b4f..762a7d6cec73de8433c58c6a6c691115e3c23e1c 100644 (file)
@@ -297,6 +297,7 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
 {
        struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
 
+       dbg_io("jhead %d", wbuf->jhead);
        wbuf->need_sync = 1;
        wbuf->c->need_wbuf_sync = 1;
        ubifs_wake_up_bgt(wbuf->c);
@@ -311,8 +312,12 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
 {
        ubifs_assert(!hrtimer_active(&wbuf->timer));
 
-       if (!ktime_to_ns(wbuf->softlimit))
+       if (wbuf->no_timer)
                return;
+       dbg_io("set timer for jhead %d, %llu-%llu millisecs", wbuf->jhead,
+              div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
+              div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
+                      USEC_PER_SEC));
        hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
                               HRTIMER_MODE_REL);
 }
@@ -323,11 +328,8 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
  */
 static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
 {
-       /*
-        * If the syncer is waiting for the lock (from the background thread's
-        * context) and another task is changing write-buffer then the syncing
-        * should be canceled.
-        */
+       if (wbuf->no_timer)
+               return;
        wbuf->need_sync = 0;
        hrtimer_cancel(&wbuf->timer);
 }
@@ -349,8 +351,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
                /* Write-buffer is empty or not seeked */
                return 0;
 
-       dbg_io("LEB %d:%d, %d bytes",
-              wbuf->lnum, wbuf->offs, wbuf->used);
+       dbg_io("LEB %d:%d, %d bytes, jhead %d",
+              wbuf->lnum, wbuf->offs, wbuf->used, wbuf->jhead);
        ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
        ubifs_assert(!(wbuf->avail & 7));
        ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
@@ -390,7 +392,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @offs: logical eraseblock offset to seek to
  * @dtype: data type
  *
- * This function targets the write buffer to logical eraseblock @lnum:@offs.
+ * This function targets the write-buffer to logical eraseblock @lnum:@offs.
  * The write-buffer is synchronized if it is not empty. Returns zero in case of
  * success and a negative error code in case of failure.
  */
@@ -399,7 +401,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
 {
        const struct ubifs_info *c = wbuf->c;
 
-       dbg_io("LEB %d:%d", lnum, offs);
+       dbg_io("LEB %d:%d, jhead %d", lnum, offs, wbuf->jhead);
        ubifs_assert(lnum >= 0 && lnum < c->leb_cnt);
        ubifs_assert(offs >= 0 && offs <= c->leb_size);
        ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
@@ -506,9 +508,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        struct ubifs_info *c = wbuf->c;
        int err, written, n, aligned_len = ALIGN(len, 8), offs;
 
-       dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len,
-              dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum,
-              wbuf->offs + wbuf->used);
+       dbg_io("%d bytes (%s) to jhead %d wbuf at LEB %d:%d", len,
+              dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->jhead,
+              wbuf->lnum, wbuf->offs + wbuf->used);
        ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
        ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
        ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
@@ -533,8 +535,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                memcpy(wbuf->buf + wbuf->used, buf, len);
 
                if (aligned_len == wbuf->avail) {
-                       dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum,
-                               wbuf->offs);
+                       dbg_io("flush jhead %d wbuf to LEB %d:%d",
+                              wbuf->jhead, wbuf->lnum, wbuf->offs);
                        err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
                                            wbuf->offs, c->min_io_size,
                                            wbuf->dtype);
@@ -562,7 +564,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
         * minimal I/O unit. We have to fill and flush write-buffer and switch
         * to the next min. I/O unit.
         */
-       dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs);
+       dbg_io("flush jhead %d wbuf to LEB %d:%d",
+              wbuf->jhead, wbuf->lnum, wbuf->offs);
        memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
        err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
                            c->min_io_size, wbuf->dtype);
@@ -695,7 +698,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
        int err, rlen, overlap;
        struct ubifs_ch *ch = buf;
 
-       dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+       dbg_io("LEB %d:%d, %s, length %d, jhead %d", lnum, offs,
+              dbg_ntype(type), len, wbuf->jhead);
        ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
        ubifs_assert(!(offs & 7) && offs < c->leb_size);
        ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
@@ -819,13 +823,12 @@ out:
  * @c: UBIFS file-system description object
  * @wbuf: write-buffer to initialize
  *
- * This function initializes write buffer. Returns zero in case of success
+ * This function initializes write-buffer. Returns zero in case of success
  * %-ENOMEM in case of failure.
  */
 int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
 {
        size_t size;
-       ktime_t hardlimit;
 
        wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
        if (!wbuf->buf)
@@ -851,22 +854,16 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
 
        hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        wbuf->timer.function = wbuf_timer_callback_nolock;
-       /*
-        * Make write-buffer soft limit to be 20% of the hard limit. The
-        * write-buffer timer is allowed to expire any time between the soft
-        * and hard limits.
-        */
-       hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
-       wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
-       wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
-       hrtimer_set_expires_range_ns(&wbuf->timer,  wbuf->softlimit,
-                                    wbuf->delta);
+       wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
+       wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
+       wbuf->delta *= 1000000000ULL;
+       ubifs_assert(wbuf->delta <= ULONG_MAX);
        return 0;
 }
 
 /**
  * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array.
- * @wbuf: the write-buffer whereto add
+ * @wbuf: the write-buffer where to add
  * @inum: the inode number
  *
  * This function adds an inode number to the inode array of the write-buffer.
index 6db7a6be6c9732a8a14cecc8ea60683522493442..8aacd64957a223c0a01e2d9c54dd73c9d7fbd409 100644 (file)
@@ -25,7 +25,6 @@
 /* This file implements EXT2-compatible extended attribute ioctl() calls */
 
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/mount.h>
 #include "ubifs.h"
 
index 805605250f128af9b6a978fa8c29c5c31660539a..e5f6cf8a115535e469a646e4806d9dcdbf19a490 100644 (file)
@@ -52,6 +52,25 @@ static int is_empty(void *buf, int len)
        return 1;
 }
 
+/**
+ * first_non_ff - find offset of the first non-0xff byte.
+ * @buf: buffer to search in
+ * @len: length of buffer
+ *
+ * This function returns offset of the first non-0xff byte in @buf or %-1 if
+ * the buffer contains only 0xff bytes.
+ */
+static int first_non_ff(void *buf, int len)
+{
+       uint8_t *p = buf;
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (*p++ != 0xff)
+                       return i;
+       return -1;
+}
+
 /**
  * get_master_node - get the last valid master node allowing for corruption.
  * @c: UBIFS file-system description object
@@ -357,11 +376,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
        empty_offs = ALIGN(offs + 1, c->min_io_size);
        check_len = c->leb_size - empty_offs;
        p = buf + empty_offs - offs;
-
-       for (; check_len > 0; check_len--)
-               if (*p++ != 0xff)
-                       return 0;
-       return 1;
+       return is_empty(p, check_len);
 }
 
 /**
@@ -543,8 +558,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
  *
  * This function does a scan of a LEB, but caters for errors that might have
  * been caused by the unclean unmount from which we are attempting to recover.
- *
- * This function returns %0 on success and a negative error code on failure.
+ * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is
+ * found, and a negative error code in case of failure.
  */
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                                         int offs, void *sbuf, int grouped)
@@ -643,7 +658,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        goto corrupted;
                default:
                        dbg_err("unknown");
-                       goto corrupted;
+                       err = -EINVAL;
+                       goto error;
                }
        }
 
@@ -652,8 +668,13 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        clean_buf(c, &buf, lnum, &offs, &len);
                        need_clean = 1;
                } else {
-                       ubifs_err("corrupt empty space at LEB %d:%d",
-                                 lnum, offs);
+                       int corruption = first_non_ff(buf, len);
+
+                       ubifs_err("corrupt empty space LEB %d:%d, corruption "
+                                 "starts at %d", lnum, offs, corruption);
+                       /* Make sure we dump interesting non-0xFF data */
+                       offs = corruption;
+                       buf += corruption;
                        goto corrupted;
                }
        }
@@ -813,7 +834,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
 static int recover_head(const struct ubifs_info *c, int lnum, int offs,
                        void *sbuf)
 {
-       int len, err, need_clean = 0;
+       int len, err;
 
        if (c->min_io_size > 1)
                len = c->min_io_size;
@@ -827,19 +848,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
 
        /* Read at the head location and check it is empty flash */
        err = ubi_read(c->ubi, lnum, sbuf, offs, len);
-       if (err)
-               need_clean = 1;
-       else {
-               uint8_t *p = sbuf;
-
-               while (len--)
-                       if (*p++ != 0xff) {
-                               need_clean = 1;
-                               break;
-                       }
-       }
-
-       if (need_clean) {
+       if (err || !is_empty(sbuf, len)) {
                dbg_rcvry("cleaning head at %d:%d", lnum, offs);
                if (offs == 0)
                        return ubifs_leb_unmap(c, lnum);
index 11cc80125a49524cef118b97173ed7ff5fb94fd9..2970500f32dfbb76ca9b8d6ff39fd8ee08fada4a 100644 (file)
@@ -837,9 +837,10 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
 
        dbg_mnt("replay log LEB %d:%d", lnum, offs);
        sleb = ubifs_scan(c, lnum, offs, sbuf);
-       if (IS_ERR(sleb)) {
-               if (c->need_recovery)
-                       sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
+       if (IS_ERR(sleb) ) {
+               if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery)
+                       return PTR_ERR(sleb);
+               sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
                if (IS_ERR(sleb))
                        return PTR_ERR(sleb);
        }
@@ -957,7 +958,7 @@ out:
        return err;
 
 out_dump:
-       ubifs_err("log error detected while replying the log at LEB %d:%d",
+       ubifs_err("log error detected while replaying the log at LEB %d:%d",
                  lnum, offs + snod->offs);
        dbg_dump_node(c, snod->node);
        ubifs_scan_destroy(sleb);
index 0ed82479b44b4daca156a80107fee1b040ec10a7..892ebfee4fe538fe033596c5d42d13860d5fe82a 100644 (file)
@@ -238,12 +238,12 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
 {
        int len;
 
-       ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
+       ubifs_err("corruption at LEB %d:%d", lnum, offs);
        if (dbg_failure_mode)
                return;
        len = c->leb_size - offs;
-       if (len > 4096)
-               len = 4096;
+       if (len > 8192)
+               len = 8192;
        dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
        print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
 }
@@ -256,7 +256,9 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
  * @sbuf: scan buffer (must be c->leb_size)
  *
  * This function scans LEB number @lnum and returns complete information about
- * its contents. Returns an error code in case of failure.
+ * its contents. Returns the scaned information in case of success and,
+ * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case
+ * of failure.
  */
 struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                                  int offs, void *sbuf)
@@ -279,7 +281,6 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                cond_resched();
 
                ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
-
                if (ret > 0) {
                        /* Padding bytes or a valid padding node */
                        offs += ret;
@@ -304,7 +305,8 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                        goto corrupted;
                default:
                        dbg_err("unknown");
-                       goto corrupted;
+                       err = -EINVAL;
+                       goto error;
                }
 
                err = ubifs_add_snod(c, sleb, buf, offs);
@@ -317,8 +319,10 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
                len -= node_len;
        }
 
-       if (offs % c->min_io_size)
-               goto corrupted;
+       if (offs % c->min_io_size) {
+               ubifs_err("empty space starts at non-aligned offset %d", offs);
+               goto corrupted;;
+       }
 
        ubifs_end_scan(c, sleb, lnum, offs);
 
index 79fad43f3c57ecc71b9d6adaf8dfd5e650e6fa08..26d2e0d8046598ed579a400293dbebd38eefc7e3 100644 (file)
@@ -797,7 +797,7 @@ static int alloc_wbufs(struct ubifs_info *c)
         * does not need to be synchronized by timer.
         */
        c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
-       c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0);
+       c->jheads[GCHD].wbuf.no_timer = 1;
 
        return 0;
 }
@@ -986,7 +986,7 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                switch (token) {
                /*
                 * %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
-                * We accepte them in order to be backware-compatible. But this
+                * We accept them in order to be backward-compatible. But this
                 * should be removed at some point.
                 */
                case Opt_fast_unmount:
@@ -1287,6 +1287,9 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_journal;
 
+       /* Calculate 'min_idx_lebs' after journal replay */
+       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
        err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
        if (err)
                goto out_orphans;
@@ -1754,10 +1757,8 @@ static void ubifs_put_super(struct super_block *sb)
 
                /* Synchronize write-buffers */
                if (c->jheads)
-                       for (i = 0; i < c->jhead_cnt; i++) {
+                       for (i = 0; i < c->jhead_cnt; i++)
                                ubifs_wbuf_sync(&c->jheads[i].wbuf);
-                               hrtimer_cancel(&c->jheads[i].wbuf.timer);
-                       }
 
                /*
                 * On fatal errors c->ro_media is set to 1, in which case we do
@@ -1975,7 +1976,8 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
-       err = bdi_register(&c->bdi, NULL, "ubifs");
+       err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d",
+                          c->vi.ubi_num, c->vi.vol_id);
        if (err)
                goto out_bdi;
 
index 1bf01d8200667503cb0f0e310fafbc4304701721..a29349094422731766fa82a95201e0f14ad3c7fb 100644 (file)
@@ -95,8 +95,9 @@
  */
 #define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
 
-/* Default write-buffer synchronization timeout in seconds */
-#define DEFAULT_WBUF_TIMEOUT_SECS 5
+/* Write-buffer synchronization timeout interval in seconds */
+#define WBUF_TIMEOUT_SOFTLIMIT 3
+#define WBUF_TIMEOUT_HARDLIMIT 5
 
 /* Maximum possible inode number (only 32-bit inodes are supported now) */
 #define MAX_INUM 0xFFFFFFFF
@@ -654,7 +655,8 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
  * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
  *         and @softlimit + @delta)
  * @timer: write-buffer timer
- * @need_sync: it is set if its timer expired and needs sync
+ * @no_timer: non-zero if this write-buffer does not have a timer
+ * @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
  * @next_ino: points to the next position of the following inode number
  * @inodes: stores the inode numbers of the nodes which are in wbuf
  *
@@ -683,7 +685,8 @@ struct ubifs_wbuf {
        ktime_t softlimit;
        unsigned long long delta;
        struct hrtimer timer;
-       int need_sync;
+       unsigned int no_timer:1;
+       unsigned int need_sync:1;
        int next_ino;
        ino_t *inodes;
 };
index 1cd3b55ee3d227d5916c18d95c2dd84a45e5285d..2d3f90afe5f14ee6ef3543d0bd6e01be014952ba 100644 (file)
@@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
                        printk(KERN_ERR "XFS: possible memory allocation "
                                        "deadlock in %s (mode:0x%x)\n",
                                        __func__, lflags);
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
 }
 
@@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
                        printk(KERN_ERR "XFS: possible memory allocation "
                                        "deadlock in %s (mode:0x%x)\n",
                                        __func__, lflags);
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
 }
 
index 1418b916fc2755306cca61e60c734154d543c82f..0c93c7ef3d187a27dbe6b8196de4aaa08be66447 100644 (file)
@@ -412,7 +412,7 @@ _xfs_buf_lookup_pages(
 
                        XFS_STATS_INC(xb_page_retries);
                        xfsbufd_wakeup(0, gfp_mask);
-                       congestion_wait(WRITE, HZ/50);
+                       congestion_wait(BLK_RW_ASYNC, HZ/50);
                        goto retry;
                }
 
index f4e25544157422812b4a1e576d3539e86b75b9bd..0542fd50764945935bd6975bc8094a8df2348601 100644 (file)
@@ -41,7 +41,6 @@
 #include "xfs_ioctl.h"
 
 #include <linux/dcache.h>
-#include <linux/smp_lock.h>
 
 static struct vm_operations_struct xfs_file_vm_ops;
 
index 9d40e879f99ea968e18e07f142519c5839392003..77ff547730af53f8da5850f05ee70866b720f4b9 100644 (file)
@@ -27,9 +27,9 @@
 #define pud_page_vaddr(pud)            pgd_page_vaddr(pud)
 
 #undef pud_free_tlb
-#define pud_free_tlb(tlb, x)            do { } while (0)
+#define pud_free_tlb(tlb, x, addr)     do { } while (0)
 #define pud_free(mm, x)                        do { } while (0)
-#define __pud_free_tlb(tlb, x)         do { } while (0)
+#define __pud_free_tlb(tlb, x, addr)   do { } while (0)
 
 #undef  pud_addr_end
 #define pud_addr_end(addr, end)                (end)
index a7cdc48e8b78703156456f8eb2472251e66c8d78..725612b793ce1d55462de9ab2158a795ab3b4faa 100644 (file)
@@ -59,7 +59,7 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
 }
-#define __pmd_free_tlb(tlb, x)                 do { } while (0)
+#define __pmd_free_tlb(tlb, x, a)              do { } while (0)
 
 #undef  pmd_addr_end
 #define pmd_addr_end(addr, end)                        (end)
index 87cf449a6df380e6be3a11fd24648ef3aefe588b..810431d8351b16c14c3d1954ddc2890866c41658 100644 (file)
@@ -52,7 +52,7 @@ static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address)
  */
 #define pud_alloc_one(mm, address)             NULL
 #define pud_free(mm, x)                                do { } while (0)
-#define __pud_free_tlb(tlb, x)                 do { } while (0)
+#define __pud_free_tlb(tlb, x, a)              do { } while (0)
 
 #undef  pud_addr_end
 #define pud_addr_end(addr, end)                        (end)
index f490e43a90b90a09e1cfe78a9f1215b66d3df74e..e43f9766259f301b2087e83d70a1e563e568edbd 100644 (file)
@@ -123,24 +123,24 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
                __tlb_remove_tlb_entry(tlb, ptep, address);     \
        } while (0)
 
-#define pte_free_tlb(tlb, ptep)                                        \
+#define pte_free_tlb(tlb, ptep, address)                       \
        do {                                                    \
                tlb->need_flush = 1;                            \
-               __pte_free_tlb(tlb, ptep);                      \
+               __pte_free_tlb(tlb, ptep, address);             \
        } while (0)
 
 #ifndef __ARCH_HAS_4LEVEL_HACK
-#define pud_free_tlb(tlb, pudp)                                        \
+#define pud_free_tlb(tlb, pudp, address)                       \
        do {                                                    \
                tlb->need_flush = 1;                            \
-               __pud_free_tlb(tlb, pudp);                      \
+               __pud_free_tlb(tlb, pudp, address);             \
        } while (0)
 #endif
 
-#define pmd_free_tlb(tlb, pmdp)                                        \
+#define pmd_free_tlb(tlb, pmdp, address)                       \
        do {                                                    \
                tlb->need_flush = 1;                            \
-               __pmd_free_tlb(tlb, pmdp);                      \
+               __pmd_free_tlb(tlb, pmdp, address);             \
        } while (0)
 
 #define tlb_migrate_finish(mm) do {} while (0)
index a553f1041cf1e1fe7210c92e5be2e5159975a65d..6ad76bf5fb40dd03b03682fa561b943ad209650d 100644 (file)
@@ -30,9 +30,7 @@
  *     EXCEPTION_TABLE(...)
  *     NOTES
  *
- *     __bss_start = .;
- *     BSS_SECTION(0, 0)
- *     __bss_stop = .;
+ *     BSS_SECTION(0, 0, 0)
  *     _end = .;
  *
  *     /DISCARD/ : {
  * bss (Block Started by Symbol) - uninitialized data
  * zeroed during startup
  */
-#define SBSS                                                           \
+#define SBSS(sbss_align)                                               \
+       . = ALIGN(sbss_align);                                          \
        .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {                         \
                *(.sbss)                                                \
                *(.scommon)                                             \
 #define BSS(bss_align)                                                 \
        . = ALIGN(bss_align);                                           \
        .bss : AT(ADDR(.bss) - LOAD_OFFSET) {                           \
-               VMLINUX_SYMBOL(__bss_start) = .;                        \
                *(.bss.page_aligned)                                    \
                *(.dynbss)                                              \
                *(.bss)                                                 \
                *(COMMON)                                               \
-               VMLINUX_SYMBOL(__bss_stop) = .;                         \
        }
 
 /*
                INIT_RAM_FS                                             \
        }
 
-#define BSS_SECTION(sbss_align, bss_align)                             \
-       SBSS                                                            \
+#define BSS_SECTION(sbss_align, bss_align, stop_align)                 \
+       . = ALIGN(sbss_align);                                          \
+       VMLINUX_SYMBOL(__bss_start) = .;                                \
+       SBSS(sbss_align)                                                \
        BSS(bss_align)                                                  \
-       . = ALIGN(4);
-
+       . = ALIGN(stop_align);                                          \
+       VMLINUX_SYMBOL(__bss_stop) = .;
index 45c18672b0936dc50c04b0cb33f105376401db2b..7174818c2c13a3a561d8ab13e28f4283d02c75d1 100644 (file)
@@ -43,6 +43,7 @@
        {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x4B48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \
index 0ec2c594868e657ad20cfaffc21227bf7ee2e18b..1d52425a61189e15c739a1009449e97022bd2eb8 100644 (file)
@@ -229,9 +229,14 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
                                  (1 << BDI_async_congested));
 }
 
-void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
-void set_bdi_congested(struct backing_dev_info *bdi, int rw);
-long congestion_wait(int rw, long timeout);
+enum {
+       BLK_RW_ASYNC    = 0,
+       BLK_RW_SYNC     = 1,
+};
+
+void clear_bdi_congested(struct backing_dev_info *bdi, int sync);
+void set_bdi_congested(struct backing_dev_info *bdi, int sync);
+long congestion_wait(int sync, long timeout);
 
 
 static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
index 49ae07951d55470bd3d03df392da7ffe5c0c387b..e7cb5dbf6c26a0daa4182c1d9eca0877583113b5 100644 (file)
@@ -70,11 +70,6 @@ enum rq_cmd_type_bits {
        REQ_TYPE_ATA_PC,
 };
 
-enum {
-       BLK_RW_ASYNC    = 0,
-       BLK_RW_SYNC     = 1,
-};
-
 /*
  * For request of type REQ_TYPE_LINUX_BLOCK, rq->cmd[0] is the opcode being
  * sent down (similar to how REQ_TYPE_BLOCK_PC means that ->cmd[] holds a
@@ -723,6 +718,7 @@ struct rq_map_data {
        int nr_entries;
        unsigned long offset;
        int null_mapped;
+       int from_user;
 };
 
 struct req_iterator {
@@ -779,18 +775,18 @@ extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
  * congested queues, and wake up anyone who was waiting for requests to be
  * put back.
  */
-static inline void blk_clear_queue_congested(struct request_queue *q, int rw)
+static inline void blk_clear_queue_congested(struct request_queue *q, int sync)
 {
-       clear_bdi_congested(&q->backing_dev_info, rw);
+       clear_bdi_congested(&q->backing_dev_info, sync);
 }
 
 /*
  * A queue has just entered congestion.  Flag that in the queue's VM-visible
  * state flags and increment the global gounter of congested queues.
  */
-static inline void blk_set_queue_congested(struct request_queue *q, int rw)
+static inline void blk_set_queue_congested(struct request_queue *q, int sync)
 {
-       set_bdi_congested(&q->backing_dev_info, rw);
+       set_bdi_congested(&q->backing_dev_info, sync);
 }
 
 extern void blk_start_queue(struct request_queue *q);
index 20a100fe2b4f3040554f3994706d8f7b238460af..3a1dbba4d3ae2da500e710387d130cd8ad5dd4c2 100644 (file)
@@ -143,12 +143,3 @@ extern void clockevents_notify(unsigned long reason, void *arg);
 #endif
 
 #endif
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-extern ktime_t clockevents_get_next_event(int cpu);
-#else
-static inline ktime_t clockevents_get_next_event(int cpu)
-{
-       return (ktime_t) { .tv64 = KTIME_MAX };
-}
-#endif
index d71f7c0f931b34b63bfacde2b06d19ffc5001616..38fe59dc89aefaa97871270371f28ff74bf8ca3f 100644 (file)
@@ -89,7 +89,6 @@ struct vc_data {
        unsigned int    vc_need_wrap    : 1;
        unsigned int    vc_can_do_color : 1;
        unsigned int    vc_report_mouse : 2;
-       unsigned int    vc_kmalloced    : 1;
        unsigned char   vc_utf          : 1;    /* Unicode UTF-8 encoding */
        unsigned char   vc_utf_count;
                 int    vc_utf_char;
index 2dac064d8359046c178f0d98bd9ea915ca369eaa..0026f267da20d6e9f1a0dc5343b978c1e5f0b6f1 100644 (file)
@@ -3,7 +3,6 @@
 
 #ifdef CONFIG_CRASH_DUMP
 #include <linux/kexec.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
 
index 0d6310657f32a41cc6f5af7150f13db9c35a51e7..655e7721580a450e93c8467316244a829cd5eace 100644 (file)
@@ -84,7 +84,7 @@ typedef int (*dm_merge_fn) (struct dm_target *ti, struct bvec_merge_data *bvm,
 
 typedef int (*iterate_devices_callout_fn) (struct dm_target *ti,
                                           struct dm_dev *dev,
-                                          sector_t physical_start,
+                                          sector_t start, sector_t len,
                                           void *data);
 
 typedef int (*dm_iterate_devices_fn) (struct dm_target *ti,
@@ -104,7 +104,7 @@ void dm_error(const char *message);
  * Combine device limits.
  */
 int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
-                        sector_t start, void *data);
+                        sector_t start, sector_t len, void *data);
 
 struct dm_dev {
        struct block_device *bdev;
index ed4e39f2c4230da03f93651f5d323f805cdb6c94..aebb81036db2d368a7b55664f5a2b9d102c5109d 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/atomic.h>
 #include <asm/device.h>
 
-#define BUS_ID_SIZE            20
-
 struct device;
 struct device_private;
 struct device_driver;
index 634a5e5aba3e219844fbffadce72b0361c794203..7499b36677985240f73743c9993c0ceadd16bc5b 100644 (file)
@@ -874,7 +874,7 @@ struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
-       int create, int extend_disksize);
+       int create);
 
 extern struct inode *ext3_iget(struct super_block *, unsigned long);
 extern int  ext3_write_inode (struct inode *, int);
index 6c3de999fb3486b56bc677c3a359f23a4a2b66bf..4d6f47b51189742aedf4c5ef3f379ff2db7aead5 100644 (file)
@@ -352,7 +352,7 @@ extern void fsnotify_unmount_inodes(struct list_head *list);
 /* put here because inotify does some weird stuff when destroying watches */
 extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
                                                    void *data, int data_is, const char *name,
-                                                   u32 cookie);
+                                                   u32 cookie, gfp_t gfp);
 
 #else
 
index 45257475623cad94c90304d82b4b5cd68bc498d8..8246c697863d72cec6bae27889d0149a88ab830f 100644 (file)
@@ -2,7 +2,9 @@
 #define LINUX_HARDIRQ_H
 
 #include <linux/preempt.h>
+#ifdef CONFIG_PREEMPT
 #include <linux/smp_lock.h>
+#endif
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <asm/hardirq.h>
index 54648e625efdff605b043a3aa766be7c2c3581ee..4759917adc71ae371da1cc3a45d46b22a55d4015 100644 (file)
@@ -448,7 +448,7 @@ extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
 
 static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
 {
-       if (likely(!timer->start_pid))
+       if (likely(!timer->start_site))
                return;
        timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
                                 timer->function, timer->start_comm, 0);
index 2721f07e93548150a195123bb13e02e1bfa4664b..35e7df1e9f309c7d1ee1aadce99660e969222980 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/irqflags.h>
 #include <linux/smp.h>
 #include <linux/percpu.h>
+#include <linux/hrtimer.h>
 
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
  * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run
  * IRQTF_DIED      - handler thread died
  * IRQTF_WARNED    - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
+ * IRQTF_AFFINITY  - irq thread is requested to adjust affinity
  */
 enum {
        IRQTF_RUNTHREAD,
        IRQTF_DIED,
        IRQTF_WARNED,
+       IRQTF_AFFINITY,
 };
 
 typedef irqreturn_t (*irq_handler_t)(int, void *);
@@ -517,6 +520,31 @@ extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
 extern void tasklet_init(struct tasklet_struct *t,
                         void (*func)(unsigned long), unsigned long data);
 
+struct tasklet_hrtimer {
+       struct hrtimer          timer;
+       struct tasklet_struct   tasklet;
+       enum hrtimer_restart    (*function)(struct hrtimer *);
+};
+
+extern void
+tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+                    enum hrtimer_restart (*function)(struct hrtimer *),
+                    clockid_t which_clock, enum hrtimer_mode mode);
+
+static inline
+int tasklet_hrtimer_start(struct tasklet_hrtimer *ttimer, ktime_t time,
+                         const enum hrtimer_mode mode)
+{
+       return hrtimer_start(&ttimer->timer, time, mode);
+}
+
+static inline
+void tasklet_hrtimer_cancel(struct tasklet_hrtimer *ttimer)
+{
+       hrtimer_cancel(&ttimer->timer);
+       tasklet_kill(&ttimer->tasklet);
+}
+
 /*
  * Autoprobing for irqs:
  *
index 7796aed6cdd5fdbb47a67b95b9a610f6417a384b..6a63807f714e197b59ad639149803af270e20e93 100644 (file)
@@ -27,6 +27,7 @@ extern void kmemleak_init(void);
 extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
                           gfp_t gfp);
 extern void kmemleak_free(const void *ptr);
+extern void kmemleak_free_part(const void *ptr, size_t size);
 extern void kmemleak_padding(const void *ptr, unsigned long offset,
                             size_t size);
 extern void kmemleak_not_leak(const void *ptr);
@@ -71,6 +72,9 @@ static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
 static inline void kmemleak_free(const void *ptr)
 {
 }
+static inline void kmemleak_free_part(const void *ptr, size_t size)
+{
+}
 static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags)
 {
 }
index 7bc1440fc47305418967134e2f65e0e23ea24572..dbf2479e808ef30e650cd23b2f52755a4cb22c37 100644 (file)
@@ -11,7 +11,7 @@
 #define LG_CLOCK_MIN_DELTA     100UL
 #define LG_CLOCK_MAX_DELTA     ULONG_MAX
 
-/*G:032 The second method of communicating with the Host is to via "struct
+/*G:031 The second method of communicating with the Host is to via "struct
  * lguest_data".  Once the Guest's initialization hypercall tells the Host where
  * this is, the Guest and Host both publish information in it. :*/
 struct lguest_data
index 3d501db36a26a52f0f960e59fc8e1a1504356c58..e5b6e33c65710a6f82593387e1f8e18663394ff4 100644 (file)
@@ -385,6 +385,7 @@ enum {
                                                    not multiple of 16 bytes */
        ATA_HORKAGE_FIRMWARE_WARN = (1 << 12),  /* firmware update warning */
        ATA_HORKAGE_1_5_GBPS    = (1 << 13),    /* force 1.5 Gbps */
+       ATA_HORKAGE_NOSETXFER   = (1 << 14),    /* skip SETXFER, SATA only */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
@@ -588,6 +589,7 @@ struct ata_device {
 #endif
        /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
        u64                     n_sectors;      /* size of device, if ATA */
+       u64                     n_native_sectors; /* native size, if ATA */
        unsigned int            class;          /* ATA_DEV_xxx */
        unsigned long           unpark_deadline;
 
index c9663c6903033bb95378bf567b91f8b6ca16242b..53b94e025c7c7ae7b167ecd1cdf836fe51c09897 100644 (file)
@@ -18,5 +18,8 @@ extern struct phy_device *of_phy_connect(struct net_device *dev,
                                         struct device_node *phy_np,
                                         void (*hndlr)(struct net_device *),
                                         u32 flags, phy_interface_t iface);
+extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
+                                        void (*hndlr)(struct net_device *),
+                                        phy_interface_t iface);
 
 #endif /* __LINUX_OF_MDIO_H */
index 5e970c7d3fd5b1c484ddc621dbbbc29921071926..bd15d7a5f5ce39474d4c845e1cb7d85bf9150bd9 100644 (file)
@@ -120,8 +120,9 @@ enum perf_counter_sample_format {
        PERF_SAMPLE_ID                          = 1U << 6,
        PERF_SAMPLE_CPU                         = 1U << 7,
        PERF_SAMPLE_PERIOD                      = 1U << 8,
+       PERF_SAMPLE_STREAM_ID                   = 1U << 9,
 
-       PERF_SAMPLE_MAX = 1U << 9,              /* non-ABI */
+       PERF_SAMPLE_MAX = 1U << 10,             /* non-ABI */
 };
 
 /*
@@ -312,16 +313,7 @@ enum perf_event_type {
         *      struct perf_event_header        header;
         *      u64                             time;
         *      u64                             id;
-        *      u64                             sample_period;
-        * };
-        */
-       PERF_EVENT_PERIOD               = 4,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u64                             time;
-        *      u64                             id;
+        *      u64                             stream_id;
         * };
         */
        PERF_EVENT_THROTTLE             = 5,
@@ -356,6 +348,7 @@ enum perf_event_type {
         *      { u64                   time;     } && PERF_SAMPLE_TIME
         *      { u64                   addr;     } && PERF_SAMPLE_ADDR
         *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
         *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
         *      { u64                   period;   } && PERF_SAMPLE_PERIOD
         *
index a84e9ff9b27e9d59cfd1f2d0e8b3403e21b07ca0..126120819a0dba4aeb931094094c27d3d80f9aa0 100644 (file)
@@ -40,7 +40,10 @@ enum {
  * Security-relevant compatibility flags that must be
  * cleared upon setuid or setgid exec:
  */
-#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE)
+#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC  | \
+                           ADDR_NO_RANDOMIZE  | \
+                           ADDR_COMPAT_LAYOUT | \
+                           MMAP_PAGE_ZERO)
 
 /*
  * Personality types.
index 7bc457593684aaad13a4e27b0759066832f130f0..26361c4c037a15f24feb2952070de8d1a9b2eab5 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef _LINUX_QUOTAOPS_
 #define _LINUX_QUOTAOPS_
 
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 
 static inline struct quota_info *sb_dqopt(struct super_block *sb)
index e73e2429a1b1cab128e1561865b3f12ca822a8e8..278777fa8a3a98fcad50cf0c17e8457e48328679 100644 (file)
@@ -99,7 +99,6 @@ enum rfkill_user_states {
 #undef RFKILL_STATE_UNBLOCKED
 #undef RFKILL_STATE_HARD_BLOCKED
 
-#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -225,7 +224,7 @@ void rfkill_destroy(struct rfkill *rfkill);
  * should be blocked) so that drivers need not keep track of the soft
  * block state -- which they might not be able to.
  */
-bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
+bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
 
 /**
  * rfkill_set_sw_state - Set the internal rfkill software block state
index 0085d758d6453bd18c58632db93e5580f92bc642..3ab08e4bb6b87c608d8e58b3f37e4260c18c1f4e 100644 (file)
@@ -209,7 +209,7 @@ extern unsigned long long time_sync_thresh;
                        ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
 #define task_contributes_to_load(task) \
                                ((task->state & TASK_UNINTERRUPTIBLE) != 0 && \
-                                (task->flags & PF_FROZEN) == 0)
+                                (task->flags & PF_FREEZING) == 0)
 
 #define __set_task_state(tsk, state_value)             \
        do { (tsk)->state = (state_value); } while (0)
@@ -498,6 +498,15 @@ struct task_cputime {
                .sum_exec_runtime = 0,                          \
        }
 
+/*
+ * Disable preemption until the scheduler is running.
+ * Reset by start_kernel()->sched_init()->init_idle().
+ *
+ * We include PREEMPT_ACTIVE to avoid cond_resched() from working
+ * before the scheduler is active -- see should_resched().
+ */
+#define INIT_PREEMPT_COUNT     (1 + PREEMPT_ACTIVE)
+
 /**
  * struct thread_group_cputimer - thread group interval timer counts
  * @cputime:           thread group interval timers.
@@ -1671,6 +1680,7 @@ extern cputime_t task_gtime(struct task_struct *p);
 #define PF_MEMALLOC    0x00000800      /* Allocating memory */
 #define PF_FLUSHER     0x00001000      /* responsible for disk writeback */
 #define PF_USED_MATH   0x00002000      /* if unset the fpu must be initialized before use */
+#define PF_FREEZING    0x00004000      /* freeze in progress. do not account to load */
 #define PF_NOFREEZE    0x00008000      /* this thread should not be frozen */
 #define PF_FROZEN      0x00010000      /* frozen for system suspend */
 #define PF_FSTRANS     0x00020000      /* inside a filesystem transaction */
index b47b3f039d147ee63cd4dbb1f99201c1e1814bb7..f2c69a2cca172aff841e6ce97656d5fa9cb412a9 100644 (file)
@@ -1342,12 +1342,12 @@ static inline int skb_network_offset(const struct sk_buff *skb)
  * shifting the start of the packet by 2 bytes. Drivers should do this
  * with:
  *
- * skb_reserve(NET_IP_ALIGN);
+ * skb_reserve(skb, NET_IP_ALIGN);
  *
  * The downside to this alignment of the IP header is that the DMA is now
  * unaligned. On some architectures the cost of an unaligned DMA is high
  * and this cost outweighs the gains made by aligning the IP header.
- * 
+ *
  * Since this trade off varies between architectures, we allow NET_IP_ALIGN
  * to be overridden.
  */
index 4dcbc2c71491ec9dc736b83c1eeedb03f4650a95..c1c862b1d01a2b41cccce3f462262ad4564ab782 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
 #include <linux/kmemtrace.h>
+#include <linux/kmemleak.h>
 
 enum stat_item {
        ALLOC_FASTPATH,         /* Allocation from cpu slab */
@@ -233,6 +234,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
        unsigned int order = get_order(size);
        void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
 
+       kmemleak_alloc(ret, size, 1, flags);
        trace_kmalloc(_THIS_IP_, ret, size, PAGE_SIZE << order, flags);
 
        return ret;
index 252b245cfcf4cb098658da65f60f02436b12902f..4be57ab03478c837bf470e7f9d9a04fccf5fad27 100644 (file)
@@ -132,6 +132,11 @@ do {                                                               \
 #endif /*__raw_spin_is_contended*/
 #endif
 
+/* The lock does not imply full memory barrier. */
+#ifndef ARCH_HAS_SMP_MB_AFTER_LOCK
+static inline void smp_mb__after_lock(void) { smp_mb(); }
+#endif
+
 /**
  * spin_unlock_wait - wait until the spinlock gets unlocked
  * @lock: the spinlock in question.
index d8910b68e1bdd981cabe3ac8c34150ae85fa0627..b99c625fddfe764754b5005d44ea79933b74fc09 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/uio.h>
 #include <asm/byteorder.h>
 #include <linux/scatterlist.h>
-#include <linux/smp_lock.h>
 
 /*
  * Buffer adjustment
index fa4242cdade86f9b956c949b5253e965e7aa74c9..80de7003d8c2340f7a71d98614eaa3ba2baa7c18 100644 (file)
@@ -321,6 +321,8 @@ asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese,
                                siginfo_t __user *uinfo,
                                const struct timespec __user *uts,
                                size_t sigsetsize);
+asmlinkage long sys_rt_tgsigqueueinfo(pid_t tgid, pid_t  pid, int sig,
+               siginfo_t __user *uinfo);
 asmlinkage long sys_kill(int pid, int sig);
 asmlinkage long sys_tgkill(int tgid, int pid, int sig);
 asmlinkage long sys_tkill(int pid, int sig);
index 1488d8c81aac6587c9edc8002f39f89d104391cf..e8c6c9136c97c4ab95fd6d39784b86e88baf80c8 100644 (file)
@@ -394,6 +394,7 @@ extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
 extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_flush_to_ldisc(struct tty_struct *tty);
 extern void tty_buffer_free_all(struct tty_struct *tty);
 extern void tty_buffer_flush(struct tty_struct *tty);
 extern void tty_buffer_init(struct tty_struct *tty);
index 84929e9140341583cbc8fd7050c4e5e5a12b8d29..b1e3c2fbfe1170fdd8fc4cdb023d628b1a0b4a43 100644 (file)
@@ -888,8 +888,6 @@ struct usb_driver {
  * struct usb_device_driver - identifies USB device driver to usbcore
  * @name: The driver name should be unique among USB drivers,
  *     and should normally be the same as the module name.
- * @nodename: Callback to provide a naming hint for a possible
- *     device node to create.
  * @probe: Called to see if the driver is willing to manage a particular
  *     device.  If it is, probe returns zero and uses dev_set_drvdata()
  *     to associate driver-specific data with the device.  If unwilling
@@ -924,6 +922,8 @@ extern struct bus_type usb_bus_type;
 /**
  * struct usb_class_driver - identifies a USB driver that wants to use the USB major number
  * @name: the usb class device name for this driver.  Will show up in sysfs.
+ * @nodename: Callback to provide a naming hint for a possible
+ *     device node to create.
  * @fops: pointer to the struct file_operations of this driver.
  * @minor_base: the start of the minor range for this driver.
  *
@@ -1046,6 +1046,8 @@ typedef void (*usb_complete_t)(struct urb *);
  *     the device driver is saying that it provided this DMA address,
  *     which the host controller driver should use in preference to the
  *     transfer_buffer.
+ * @sg: scatter gather buffer list
+ * @num_sgs: number of entries in the sg list
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
  *     be broken up into chunks according to the current maximum packet
  *     size for the endpoint, which is a function of the configuration
diff --git a/include/linux/usb/langwell_otg.h b/include/linux/usb/langwell_otg.h
deleted file mode 100644 (file)
index e115ae6..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Intel Langwell USB OTG transceiver driver
- * Copyright (C) 2008, 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.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#ifndef __LANGWELL_OTG_H__
-#define __LANGWELL_OTG_H__
-
-/* notify transceiver driver about OTG events */
-extern void langwell_update_transceiver(void);
-/* HCD register bus driver */
-extern int langwell_register_host(struct pci_driver *host_driver);
-/* HCD unregister bus driver */
-extern void langwell_unregister_host(struct pci_driver *host_driver);
-/* DCD register bus driver */
-extern int langwell_register_peripheral(struct pci_driver *client_driver);
-/* DCD unregister bus driver */
-extern void langwell_unregister_peripheral(struct pci_driver *client_driver);
-/* No silent failure, output warning message */
-extern void langwell_otg_nsf_msg(unsigned long message);
-
-#define CI_USBCMD              0x30
-#      define USBCMD_RST               BIT(1)
-#      define USBCMD_RS                BIT(0)
-#define CI_USBSTS              0x34
-#      define USBSTS_SLI               BIT(8)
-#      define USBSTS_URI               BIT(6)
-#      define USBSTS_PCI               BIT(2)
-#define CI_PORTSC1             0x74
-#      define PORTSC_PP                BIT(12)
-#      define PORTSC_LS                (BIT(11) | BIT(10))
-#      define PORTSC_SUSP              BIT(7)
-#      define PORTSC_CCS               BIT(0)
-#define CI_HOSTPC1             0xb4
-#      define HOSTPC1_PHCD             BIT(22)
-#define CI_OTGSC               0xf4
-#      define OTGSC_DPIE               BIT(30)
-#      define OTGSC_1MSE               BIT(29)
-#      define OTGSC_BSEIE              BIT(28)
-#      define OTGSC_BSVIE              BIT(27)
-#      define OTGSC_ASVIE              BIT(26)
-#      define OTGSC_AVVIE              BIT(25)
-#      define OTGSC_IDIE               BIT(24)
-#      define OTGSC_DPIS               BIT(22)
-#      define OTGSC_1MSS               BIT(21)
-#      define OTGSC_BSEIS              BIT(20)
-#      define OTGSC_BSVIS              BIT(19)
-#      define OTGSC_ASVIS              BIT(18)
-#      define OTGSC_AVVIS              BIT(17)
-#      define OTGSC_IDIS               BIT(16)
-#      define OTGSC_DPS                BIT(14)
-#      define OTGSC_1MST               BIT(13)
-#      define OTGSC_BSE                BIT(12)
-#      define OTGSC_BSV                BIT(11)
-#      define OTGSC_ASV                BIT(10)
-#      define OTGSC_AVV                BIT(9)
-#      define OTGSC_ID                 BIT(8)
-#      define OTGSC_HABA               BIT(7)
-#      define OTGSC_HADP               BIT(6)
-#      define OTGSC_IDPU               BIT(5)
-#      define OTGSC_DP                 BIT(4)
-#      define OTGSC_OT                 BIT(3)
-#      define OTGSC_HAAR               BIT(2)
-#      define OTGSC_VC                 BIT(1)
-#      define OTGSC_VD                 BIT(0)
-#      define OTGSC_INTEN_MASK         (0x7f << 24)
-#      define OTGSC_INTSTS_MASK        (0x7f << 16)
-#define CI_USBMODE             0xf8
-#      define USBMODE_CM               (BIT(1) | BIT(0))
-#      define USBMODE_IDLE             0
-#      define USBMODE_DEVICE           0x2
-#      define USBMODE_HOST             0x3
-
-#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
-
-struct otg_hsm {
-       /* Input */
-       int a_bus_resume;
-       int a_bus_suspend;
-       int a_conn;
-       int a_sess_vld;
-       int a_srp_det;
-       int a_vbus_vld;
-       int b_bus_resume;
-       int b_bus_suspend;
-       int b_conn;
-       int b_se0_srp;
-       int b_sess_end;
-       int b_sess_vld;
-       int id;
-
-       /* Internal variables */
-       int a_set_b_hnp_en;
-       int b_srp_done;
-       int b_hnp_enable;
-
-       /* Timeout indicator for timers */
-       int a_wait_vrise_tmout;
-       int a_wait_bcon_tmout;
-       int a_aidl_bdis_tmout;
-       int b_ase0_brst_tmout;
-       int b_bus_suspend_tmout;
-       int b_srp_res_tmout;
-
-       /* Informative variables */
-       int a_bus_drop;
-       int a_bus_req;
-       int a_clr_err;
-       int a_suspend_req;
-       int b_bus_req;
-
-       /* Output */
-       int drv_vbus;
-       int loc_conn;
-       int loc_sof;
-
-       /* Others */
-       int b_bus_suspend_vld;
-};
-
-#define TA_WAIT_VRISE  100
-#define TA_WAIT_BCON   30000
-#define TA_AIDL_BDIS   15000
-#define TB_ASE0_BRST   5000
-#define TB_SE0_SRP     2
-#define TB_SRP_RES     100
-#define TB_BUS_SUSPEND 500
-
-struct langwell_otg_timer {
-       unsigned long expires;  /* Number of count increase to timeout */
-       unsigned long count;    /* Tick counter */
-       void (*function)(unsigned long);        /* Timeout function */
-       unsigned long data;     /* Data passed to function */
-       struct list_head list;
-};
-
-struct langwell_otg {
-       struct otg_transceiver  otg;
-       struct otg_hsm          hsm;
-       void __iomem            *regs;
-       unsigned                region;
-       struct pci_driver       *host_ops;
-       struct pci_driver       *client_ops;
-       struct pci_dev          *pdev;
-       struct work_struct      work;
-       struct workqueue_struct *qwork;
-       spinlock_t              lock;
-       spinlock_t              wq_lock;
-};
-
-static inline struct langwell_otg *otg_to_langwell(struct otg_transceiver *otg)
-{
-       return container_of(otg, struct langwell_otg, otg);
-}
-
-#ifdef DEBUG
-#define otg_dbg(fmt, args...) \
-       printk(KERN_DEBUG fmt , ## args)
-#else
-#define otg_dbg(fmt, args...) \
-       do { } while (0)
-#endif /* DEBUG */
-#endif /* __LANGWELL_OTG_H__ */
index 44801d26a37a7888d7ebd88dbb5cf0e4a1836de0..0ec50ba62139e5bde97db61a10b8585c2882c916 100644 (file)
@@ -317,7 +317,8 @@ extern int usb_serial_generic_register(int debug);
 extern void usb_serial_generic_deregister(void);
 extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
                                                 gfp_t mem_flags);
-extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
+extern int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+                                       struct usb_serial_port *port,
                                        unsigned int ch);
 extern int usb_serial_handle_break(struct usb_serial_port *port);
 
index 95846d988011469be4f2050814e4acb924909c69..74f16876f38d643eb6b9df7c548b1b90131c6794 100644 (file)
@@ -338,6 +338,7 @@ struct v4l2_pix_format {
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
 #define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
 #define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
 #define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
 #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
index cec79adbe3ea60934ad69f3ef00484f12b97b065..9c543d6ac535699cf8bab7a4c7209a997cc8e8d1 100644 (file)
@@ -27,6 +27,7 @@
 #define VIRTIO_NET_F_CTRL_VQ   17      /* Control channel available */
 #define VIRTIO_NET_F_CTRL_RX   18      /* Control channel RX mode support */
 #define VIRTIO_NET_F_CTRL_VLAN 19      /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 20  /* Extra RX mode control support */
 
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 
@@ -81,14 +82,19 @@ typedef __u8 virtio_net_ctrl_ack;
 #define VIRTIO_NET_ERR    1
 
 /*
- * Control the RX mode, ie. promisucous and allmulti.  PROMISC and
- * ALLMULTI commands require an "out" sg entry containing a 1 byte
- * state value, zero = disable, non-zero = enable.  These commands
- * are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Control the RX mode, ie. promisucous, allmulti, etc...
+ * All commands require an "out" sg entry containing a 1 byte
+ * state value, zero = disable, non-zero = enable.  Commands
+ * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
  */
 #define VIRTIO_NET_CTRL_RX    0
  #define VIRTIO_NET_CTRL_RX_PROMISC      0
  #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+ #define VIRTIO_NET_CTRL_RX_ALLUNI       2
+ #define VIRTIO_NET_CTRL_RX_NOMULTI      3
+ #define VIRTIO_NET_CTRL_RX_NOUNI        4
+ #define VIRTIO_NET_CTRL_RX_NOBCAST      5
 
 /*
  * Control the MAC filter table.
index 11a4a2d3e364f355e32c21dd3fca6df8576cc261..94e908c0d7a0e4ff2e51428b85136ef38a5c51b7 100644 (file)
@@ -60,6 +60,10 @@ enum {
        V4L2_IDENT_OV7670 = 250,
        V4L2_IDENT_OV7720 = 251,
        V4L2_IDENT_OV7725 = 252,
+       V4L2_IDENT_OV7660 = 253,
+       V4L2_IDENT_OV9650 = 254,
+       V4L2_IDENT_OV9655 = 255,
+       V4L2_IDENT_SOI968 = 256,
 
        /* module saa7146: reserved range 300-309 */
        V4L2_IDENT_SAA7146 = 300,
@@ -161,6 +165,9 @@ enum {
        /* module tw9910: just ident 9910 */
        V4L2_IDENT_TW9910 = 9910,
 
+       /* module sn9c20x: just ident 10000 */
+       V4L2_IDENT_SN9C20X = 10000,
+
        /* module msp3400: reserved range 34000-34999 and 44000-44999 */
        V4L2_IDENT_MSPX4XX  = 34000, /* generic MSPX4XX identifier, only
                                        use internally (tveeprom.c). */
@@ -237,6 +244,11 @@ enum {
        V4L2_IDENT_MT9V022IX7ATC        = 45010, /* No way to detect "normal" I77ATx */
        V4L2_IDENT_MT9V022IX7ATM        = 45015, /* and "lead free" IA7ATx chips */
        V4L2_IDENT_MT9T031              = 45020,
+       V4L2_IDENT_MT9V111              = 45031,
+       V4L2_IDENT_MT9V112              = 45032,
+
+       /* HV7131R CMOS sensor: just ident 46000 */
+       V4L2_IDENT_HV7131R              = 46000,
 
        /* module cs53132a: just ident 53132 */
        V4L2_IDENT_CS53l32A = 53132,
index cbd5364b2c8a94237d4554818a7fcd87783c1a8b..5ba9f02731eb353921854816bd503bb04978c298 100644 (file)
@@ -156,7 +156,7 @@ extern int  sysctl_rose_maximum_vcs;
 extern int  sysctl_rose_window_size;
 extern int  rosecmp(rose_address *, rose_address *);
 extern int  rosecmpm(rose_address *, rose_address *, unsigned short);
-extern const char *rose2asc(const rose_address *);
+extern char *rose2asc(char *buf, const rose_address *);
 extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *);
 extern void rose_kill_by_neigh(struct rose_neigh *);
 extern unsigned int rose_new_lci(struct rose_neigh *);
index 352f06bbd7a9b14b0257b8014d4ecf3027aad44e..950409dcec3d5763bf4822c4fb8599e20808c728 100644 (file)
@@ -54,6 +54,7 @@
 
 #include <linux/filter.h>
 #include <linux/rculist_nulls.h>
+#include <linux/poll.h>
 
 #include <asm/atomic.h>
 #include <net/dst.h>
@@ -103,15 +104,15 @@ struct net;
 
 /**
  *     struct sock_common - minimal network layer representation of sockets
+ *     @skc_node: main hash linkage for various protocol lookup tables
+ *     @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
+ *     @skc_refcnt: reference count
+ *     @skc_hash: hash value used with various protocol lookup tables
  *     @skc_family: network address family
  *     @skc_state: Connection state
  *     @skc_reuse: %SO_REUSEADDR setting
  *     @skc_bound_dev_if: bound device index if != 0
- *     @skc_node: main hash linkage for various protocol lookup tables
- *     @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
  *     @skc_bind_node: bind hash linkage for various protocol lookup tables
- *     @skc_refcnt: reference count
- *     @skc_hash: hash value used with various protocol lookup tables
  *     @skc_prot: protocol handlers inside a network family
  *     @skc_net: reference to the network namespace of this socket
  *
@@ -119,17 +120,21 @@ struct net;
  *     for struct sock and struct inet_timewait_sock.
  */
 struct sock_common {
-       unsigned short          skc_family;
-       volatile unsigned char  skc_state;
-       unsigned char           skc_reuse;
-       int                     skc_bound_dev_if;
+       /*
+        * first fields are not copied in sock_copy()
+        */
        union {
                struct hlist_node       skc_node;
                struct hlist_nulls_node skc_nulls_node;
        };
-       struct hlist_node       skc_bind_node;
        atomic_t                skc_refcnt;
+
        unsigned int            skc_hash;
+       unsigned short          skc_family;
+       volatile unsigned char  skc_state;
+       unsigned char           skc_reuse;
+       int                     skc_bound_dev_if;
+       struct hlist_node       skc_bind_node;
        struct proto            *skc_prot;
 #ifdef CONFIG_NET_NS
        struct net              *skc_net;
@@ -207,15 +212,17 @@ struct sock {
         * don't add nothing before this first member (__sk_common) --acme
         */
        struct sock_common      __sk_common;
+#define sk_node                        __sk_common.skc_node
+#define sk_nulls_node          __sk_common.skc_nulls_node
+#define sk_refcnt              __sk_common.skc_refcnt
+
+#define sk_copy_start          __sk_common.skc_hash
+#define sk_hash                        __sk_common.skc_hash
 #define sk_family              __sk_common.skc_family
 #define sk_state               __sk_common.skc_state
 #define sk_reuse               __sk_common.skc_reuse
 #define sk_bound_dev_if                __sk_common.skc_bound_dev_if
-#define sk_node                        __sk_common.skc_node
-#define sk_nulls_node          __sk_common.skc_nulls_node
 #define sk_bind_node           __sk_common.skc_bind_node
-#define sk_refcnt              __sk_common.skc_refcnt
-#define sk_hash                        __sk_common.skc_hash
 #define sk_prot                        __sk_common.skc_prot
 #define sk_net                 __sk_common.skc_net
        kmemcheck_bitfield_begin(flags);
@@ -1241,6 +1248,74 @@ static inline int sk_has_allocations(const struct sock *sk)
        return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk);
 }
 
+/**
+ * sk_has_sleeper - check if there are any waiting processes
+ * @sk: socket
+ *
+ * Returns true if socket has waiting processes
+ *
+ * The purpose of the sk_has_sleeper and sock_poll_wait is to wrap the memory
+ * barrier call. They were added due to the race found within the tcp code.
+ *
+ * Consider following tcp code paths:
+ *
+ * CPU1                  CPU2
+ *
+ * sys_select            receive packet
+ *   ...                 ...
+ *   __add_wait_queue    update tp->rcv_nxt
+ *   ...                 ...
+ *   tp->rcv_nxt check   sock_def_readable
+ *   ...                 {
+ *   schedule               ...
+ *                          if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ *                              wake_up_interruptible(sk->sk_sleep)
+ *                          ...
+ *                       }
+ *
+ * The race for tcp fires when the __add_wait_queue changes done by CPU1 stay
+ * in its cache, and so does the tp->rcv_nxt update on CPU2 side.  The CPU1
+ * could then endup calling schedule and sleep forever if there are no more
+ * data on the socket.
+ *
+ * The sk_has_sleeper is always called right after a call to read_lock, so we
+ * can use smp_mb__after_lock barrier.
+ */
+static inline int sk_has_sleeper(struct sock *sk)
+{
+       /*
+        * We need to be sure we are in sync with the
+        * add_wait_queue modifications to the wait queue.
+        *
+        * This memory barrier is paired in the sock_poll_wait.
+        */
+       smp_mb__after_lock();
+       return sk->sk_sleep && waitqueue_active(sk->sk_sleep);
+}
+
+/**
+ * sock_poll_wait - place memory barrier behind the poll_wait call.
+ * @filp:           file
+ * @wait_address:   socket wait queue
+ * @p:              poll_table
+ *
+ * See the comments in the sk_has_sleeper function.
+ */
+static inline void sock_poll_wait(struct file *filp,
+               wait_queue_head_t *wait_address, poll_table *p)
+{
+       if (p && wait_address) {
+               poll_wait(filp, wait_address, p);
+               /*
+                * We need to be sure we are in sync with the
+                * socket flags modification.
+                *
+                * This memory barrier is paired in the sk_has_sleeper.
+               */
+               smp_mb();
+       }
+}
+
 /*
  *     Queue a received datagram if it will fit. Stream and sequenced
  *     protocols can't normally use this as they need to fit buffers in
index 19f4150f4d4d166380f95079c1877af28e6d62a5..88af843064710bf43e25cb6932aa40479c19e07e 100644 (file)
@@ -1425,6 +1425,11 @@ struct tcp_request_sock_ops {
 #ifdef CONFIG_TCP_MD5SIG
        struct tcp_md5sig_key   *(*md5_lookup) (struct sock *sk,
                                                struct request_sock *req);
+       int                     (*calc_md5_hash) (char *location,
+                                                 struct tcp_md5sig_key *md5,
+                                                 struct sock *sk,
+                                                 struct request_sock *req,
+                                                 struct sk_buff *skb);
 #endif
 };
 
index d6b05f42dd44d85e488eaa65c67a105e1e7ad36c..9a74b468a2291dd19e0ee3b8ad364943b3a8b4bb 100644 (file)
@@ -1,3 +1,6 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM block
+
 #if !defined(_TRACE_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_BLOCK_H
 
@@ -5,9 +8,6 @@
 #include <linux/blkdev.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM block
-
 TRACE_EVENT(block_rq_abort,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
index acf4cc9cd36d015e877887e13b79802eb9e8590d..7d8b5bc741857401acf0ee81f8eaa9b98b52c1cd 100644 (file)
@@ -1,9 +1,9 @@
-#if !defined(_TRACE_EXT4_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_EXT4_H
-
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM ext4
 
+#if !defined(_TRACE_EXT4_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EXT4_H
+
 #include <linux/writeback.h>
 #include "../../../fs/ext4/ext4.h"
 #include "../../../fs/ext4/mballoc.h"
@@ -34,7 +34,8 @@ TRACE_EVENT(ext4_free_inode,
 
        TP_printk("dev %s ino %lu mode %d uid %u gid %u blocks %llu",
                  jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->mode,
-                 __entry->uid, __entry->gid, __entry->blocks)
+                 __entry->uid, __entry->gid,
+                 (unsigned long long) __entry->blocks)
 );
 
 TRACE_EVENT(ext4_request_inode,
@@ -189,7 +190,7 @@ TRACE_EVENT(ext4_journalled_write_end,
                  __entry->copied)
 );
 
-TRACE_EVENT(ext4_da_writepage,
+TRACE_EVENT(ext4_writepage,
        TP_PROTO(struct inode *inode, struct page *page),
 
        TP_ARGS(inode, page),
@@ -341,49 +342,6 @@ TRACE_EVENT(ext4_da_write_end,
                  __entry->copied)
 );
 
-TRACE_EVENT(ext4_normal_writepage,
-       TP_PROTO(struct inode *inode, struct page *page),
-
-       TP_ARGS(inode, page),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        pgoff_t, index                  )
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->index  = page->index;
-       ),
-
-       TP_printk("dev %s ino %lu page_index %lu",
-                 jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->index)
-);
-
-TRACE_EVENT(ext4_journalled_writepage,
-       TP_PROTO(struct inode *inode, struct page *page),
-
-       TP_ARGS(inode, page),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        pgoff_t, index                  )
-
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->index  = page->index;
-       ),
-
-       TP_printk("dev %s ino %lu page_index %lu",
-                 jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->index)
-);
-
 TRACE_EVENT(ext4_discard_blocks,
        TP_PROTO(struct super_block *sb, unsigned long long blk,
                        unsigned long long count),
index b0c7ede55eb156c0d4880dee2555dc4b35577887..1cb0c3aa11e613659a0a87cc9c72ea4d14f69a3f 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq
+
 #if !defined(_TRACE_IRQ_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_IRQ_H
 
 #include <linux/tracepoint.h>
 #include <linux/interrupt.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM irq
-
 #define softirq_name(sirq) { sirq##_SOFTIRQ, #sirq }
 #define show_softirq_name(val)                 \
        __print_symbolic(val,                   \
index 845b0b4b48fda1077b851f44a99042d79f2e7591..10813fa0c8d07b68035b3bdc287fe0e0304a7788 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM jbd2
+
 #if !defined(_TRACE_JBD2_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_JBD2_H
 
 #include <linux/jbd2.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM jbd2
-
 TRACE_EVENT(jbd2_checkpoint,
 
        TP_PROTO(journal_t *journal, int result),
index 9baba50d6512e594658485779244bbdde751916b..1493c541f9c44566a21553c5947aa1fa93fc702e 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kmem
+
 #if !defined(_TRACE_KMEM_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_KMEM_H
 
 #include <linux/types.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM kmem
-
 /*
  * The order of these masks is important. Matching masks will be seen
  * first and the left over flags will end up showing by themselves.
index 0e956c9dfd7eed1676d049ab2f1c6375983ba556..bcf1d209a00dabf7838aae49c2e5edcc5fc6dde8 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM lockdep
+
 #if !defined(_TRACE_LOCKDEP_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_LOCKDEP_H
 
 #include <linux/lockdep.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM lockdep
-
 #ifdef CONFIG_LOCKDEP
 
 TRACE_EVENT(lock_acquire,
index 24ab5bcff7b2bfaebfe7ed4d544f286c43c416a3..8949bb7eb08278bbe30d6785a1e6c1902db8a99a 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sched
+
 #if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_SCHED_H
 
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM sched
-
 /*
  * Tracepoint for calling kthread_stop, performed to end a kthread:
  */
index 1e8fabb57c06e4db8f46704153642bf873f87f77..e499863b96693b108fef4c2bc5b07fd52624ba63 100644 (file)
@@ -1,12 +1,12 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM skb
+
 #if !defined(_TRACE_SKB_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_SKB_H
 
 #include <linux/skbuff.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM skb
-
 /*
  * Tracepoint for free an sk_buff:
  */
index 035f1bff288e66586c2d4697e1bc8d5e0ee9329e..fcfd9a1e4b9640a7c4d3e26c44f2aac38e3b6810 100644 (file)
@@ -1,3 +1,6 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM workqueue
+
 #if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_WORKQUEUE_H
 
@@ -5,9 +8,6 @@
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM workqueue
-
 TRACE_EVENT(workqueue_insertion,
 
        TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
index 1ce05a4cb5f6ffb945391dd93c8e7e172d511d8f..cb2c092702260def4bd2dfe8a2bb4334ea57fbb2 100644 (file)
@@ -962,7 +962,7 @@ config PERF_COUNTERS
 
 config EVENT_PROFILE
        bool "Tracepoint profile sources"
-       depends on PERF_COUNTERS && EVENT_TRACER
+       depends on PERF_COUNTERS && EVENT_TRACING
        default y
 
 endmenu
index bd2959228871d05926dbb0ddfc3b5fe4f54c59d9..9b42695f0d1484a1a7ee405b9aa73996d29da7ae 100644 (file)
@@ -1407,14 +1407,11 @@ long do_fork(unsigned long clone_flags,
                if (clone_flags & CLONE_VFORK) {
                        p->vfork_done = &vfork;
                        init_completion(&vfork);
-               } else if (!(clone_flags & CLONE_VM)) {
-                       /*
-                        * vfork will do an exec which will call
-                        * set_task_comm()
-                        */
-                       perf_counter_fork(p);
                }
 
+               if (!(clone_flags & CLONE_THREAD))
+                       perf_counter_fork(p);
+
                audit_finish_fork(p);
                tracehook_report_clone(regs, clone_flags, nr, p);
 
index 2f4936cf708367c90f3d16fe5a4d9b49ec66e90e..bd1d42b17cb2f52f5156506ba25d75376102af7f 100644 (file)
@@ -44,12 +44,19 @@ void refrigerator(void)
        recalc_sigpending(); /* We sent fake signal, clean it up */
        spin_unlock_irq(&current->sighand->siglock);
 
+       /* prevent accounting of that task to load */
+       current->flags |= PF_FREEZING;
+
        for (;;) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                if (!frozen(current))
                        break;
                schedule();
        }
+
+       /* Remove the accounting blocker */
+       current->flags &= ~PF_FREEZING;
+
        pr_debug("%s left refrigerator\n", current->comm);
        __set_current_state(save);
 }
index 794c862125feff034a231d4f16a5106189625d10..0672ff88f159f3041206750b3427fdd68aa0afc1 100644 (file)
@@ -247,6 +247,7 @@ again:
        if (err < 0)
                return err;
 
+       page = compound_head(page);
        lock_page(page);
        if (!page->mapping) {
                unlock_page(page);
index 9002958a96e70ef0f8acc70ceeccac5327efae9e..49da79ab8486df682bc7f252674b4a01b810c108 100644 (file)
@@ -191,6 +191,46 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
        }
 }
 
+
+/*
+ * Get the preferred target CPU for NOHZ
+ */
+static int hrtimer_get_target(int this_cpu, int pinned)
+{
+#ifdef CONFIG_NO_HZ
+       if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) {
+               int preferred_cpu = get_nohz_load_balancer();
+
+               if (preferred_cpu >= 0)
+                       return preferred_cpu;
+       }
+#endif
+       return this_cpu;
+}
+
+/*
+ * With HIGHRES=y we do not migrate the timer when it is expiring
+ * before the next event on the target cpu because we cannot reprogram
+ * the target cpu hardware and we would cause it to fire late.
+ *
+ * Called with cpu_base->lock of target cpu held.
+ */
+static int
+hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base)
+{
+#ifdef CONFIG_HIGH_RES_TIMERS
+       ktime_t expires;
+
+       if (!new_base->cpu_base->hres_active)
+               return 0;
+
+       expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset);
+       return expires.tv64 <= new_base->cpu_base->expires_next.tv64;
+#else
+       return 0;
+#endif
+}
+
 /*
  * Switch the timer base to the current CPU when possible.
  */
@@ -200,16 +240,8 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
 {
        struct hrtimer_clock_base *new_base;
        struct hrtimer_cpu_base *new_cpu_base;
-       int cpu, preferred_cpu = -1;
-
-       cpu = smp_processor_id();
-#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
-       if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
-               preferred_cpu = get_nohz_load_balancer();
-               if (preferred_cpu >= 0)
-                       cpu = preferred_cpu;
-       }
-#endif
+       int this_cpu = smp_processor_id();
+       int cpu = hrtimer_get_target(this_cpu, pinned);
 
 again:
        new_cpu_base = &per_cpu(hrtimer_bases, cpu);
@@ -217,7 +249,7 @@ again:
 
        if (base != new_base) {
                /*
-                * We are trying to schedule the timer on the local CPU.
+                * We are trying to move timer to new_base.
                 * However we can't change timer's base while it is running,
                 * so we keep it on the same CPU. No hassle vs. reprogramming
                 * the event source in the high resolution case. The softirq
@@ -233,38 +265,12 @@ again:
                spin_unlock(&base->cpu_base->lock);
                spin_lock(&new_base->cpu_base->lock);
 
-               /* Optimized away for NOHZ=n SMP=n */
-               if (cpu == preferred_cpu) {
-                       /* Calculate clock monotonic expiry time */
-#ifdef CONFIG_HIGH_RES_TIMERS
-                       ktime_t expires = ktime_sub(hrtimer_get_expires(timer),
-                                                       new_base->offset);
-#else
-                       ktime_t expires = hrtimer_get_expires(timer);
-#endif
-
-                       /*
-                        * Get the next event on target cpu from the
-                        * clock events layer.
-                        * This covers the highres=off nohz=on case as well.
-                        */
-                       ktime_t next = clockevents_get_next_event(cpu);
-
-                       ktime_t delta = ktime_sub(expires, next);
-
-                       /*
-                        * We do not migrate the timer when it is expiring
-                        * before the next event on the target cpu because
-                        * we cannot reprogram the target cpu hardware and
-                        * we would cause it to fire late.
-                        */
-                       if (delta.tv64 < 0) {
-                               cpu = smp_processor_id();
-                               spin_unlock(&new_base->cpu_base->lock);
-                               spin_lock(&base->cpu_base->lock);
-                               timer->base = base;
-                               goto again;
-                       }
+               if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+                       cpu = this_cpu;
+                       spin_unlock(&new_base->cpu_base->lock);
+                       spin_lock(&base->cpu_base->lock);
+                       timer->base = base;
+                       goto again;
                }
                timer->base = new_base;
        }
@@ -1276,14 +1282,22 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
        expires_next.tv64 = KTIME_MAX;
 
+       spin_lock(&cpu_base->lock);
+       /*
+        * We set expires_next to KTIME_MAX here with cpu_base->lock
+        * held to prevent that a timer is enqueued in our queue via
+        * the migration code. This does not affect enqueueing of
+        * timers which run their callback and need to be requeued on
+        * this CPU.
+        */
+       cpu_base->expires_next.tv64 = KTIME_MAX;
+
        base = cpu_base->clock_base;
 
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
                ktime_t basenow;
                struct rb_node *node;
 
-               spin_lock(&cpu_base->lock);
-
                basenow = ktime_add(now, base->offset);
 
                while ((node = base->first)) {
@@ -1316,11 +1330,15 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
                        __run_hrtimer(timer);
                }
-               spin_unlock(&cpu_base->lock);
                base++;
        }
 
+       /*
+        * Store the new expiry value so the migration code can verify
+        * against it.
+        */
        cpu_base->expires_next = expires_next;
+       spin_unlock(&cpu_base->lock);
 
        /* Reprogramming necessary ? */
        if (expires_next.tv64 != KTIME_MAX) {
index 73468253143ba55883072d1020791c11b1e30210..e70ed5592eb90e406c201e5d2881be679a5fc278 100644 (file)
@@ -42,8 +42,7 @@ static inline void unregister_handler_proc(unsigned int irq,
 
 extern int irq_select_affinity_usr(unsigned int irq);
 
-extern void
-irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask);
+extern void irq_set_thread_affinity(struct irq_desc *desc);
 
 /*
  * Debugging printout:
index 50da676729013dfe8dbc7929a4fdec16412f7780..61c679db4687a853c52f7d5b23b5ba5e267b4c17 100644 (file)
@@ -80,14 +80,22 @@ int irq_can_set_affinity(unsigned int irq)
        return 1;
 }
 
-void
-irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask)
+/**
+ *     irq_set_thread_affinity - Notify irq threads to adjust affinity
+ *     @desc:          irq descriptor which has affitnity changed
+ *
+ *     We just set IRQTF_AFFINITY and delegate the affinity setting
+ *     to the interrupt thread itself. We can not call
+ *     set_cpus_allowed_ptr() here as we hold desc->lock and this
+ *     code can be called from hard interrupt context.
+ */
+void irq_set_thread_affinity(struct irq_desc *desc)
 {
        struct irqaction *action = desc->action;
 
        while (action) {
                if (action->thread)
-                       set_cpus_allowed_ptr(action->thread, cpumask);
+                       set_bit(IRQTF_AFFINITY, &action->thread_flags);
                action = action->next;
        }
 }
@@ -112,7 +120,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
        if (desc->status & IRQ_MOVE_PCNTXT) {
                if (!desc->chip->set_affinity(irq, cpumask)) {
                        cpumask_copy(desc->affinity, cpumask);
-                       irq_set_thread_affinity(desc, cpumask);
+                       irq_set_thread_affinity(desc);
                }
        }
        else {
@@ -122,7 +130,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 #else
        if (!desc->chip->set_affinity(irq, cpumask)) {
                cpumask_copy(desc->affinity, cpumask);
-               irq_set_thread_affinity(desc, cpumask);
+               irq_set_thread_affinity(desc);
        }
 #endif
        desc->status |= IRQ_AFFINITY_SET;
@@ -176,7 +184,7 @@ int irq_select_affinity_usr(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        ret = setup_affinity(irq, desc);
        if (!ret)
-               irq_set_thread_affinity(desc, desc->affinity);
+               irq_set_thread_affinity(desc);
        spin_unlock_irqrestore(&desc->lock, flags);
 
        return ret;
@@ -443,6 +451,39 @@ static int irq_wait_for_interrupt(struct irqaction *action)
        return -1;
 }
 
+#ifdef CONFIG_SMP
+/*
+ * Check whether we need to change the affinity of the interrupt thread.
+ */
+static void
+irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
+{
+       cpumask_var_t mask;
+
+       if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))
+               return;
+
+       /*
+        * In case we are out of memory we set IRQTF_AFFINITY again and
+        * try again next time
+        */
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
+               set_bit(IRQTF_AFFINITY, &action->thread_flags);
+               return;
+       }
+
+       spin_lock_irq(&desc->lock);
+       cpumask_copy(mask, desc->affinity);
+       spin_unlock_irq(&desc->lock);
+
+       set_cpus_allowed_ptr(current, mask);
+       free_cpumask_var(mask);
+}
+#else
+static inline void
+irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
+#endif
+
 /*
  * Interrupt handler thread
  */
@@ -458,6 +499,8 @@ static int irq_thread(void *data)
 
        while (!irq_wait_for_interrupt(action)) {
 
+               irq_thread_check_affinity(desc, action);
+
                atomic_inc(&desc->threads_active);
 
                spin_lock_irq(&desc->lock);
index cfe767ca154501460f9f7e757c08d881611e9c95..fcb6c96f2627297654e9c3336e7f349846205752 100644 (file)
@@ -45,7 +45,7 @@ void move_masked_irq(int irq)
                   < nr_cpu_ids))
                if (!desc->chip->set_affinity(irq, desc->pending_mask)) {
                        cpumask_copy(desc->affinity, desc->pending_mask);
-                       irq_set_thread_affinity(desc, desc->pending_mask);
+                       irq_set_thread_affinity(desc);
                }
 
        cpumask_clear(desc->pending_mask);
index c0fa54b276d951042f69febb6df8c27190850dd9..16b5739c516aa831d11755a93895f6b4d4e91001 100644 (file)
@@ -237,13 +237,9 @@ static int __kprobes collect_garbage_slots(void)
 {
        struct kprobe_insn_page *kip;
        struct hlist_node *pos, *next;
-       int safety;
 
        /* Ensure no-one is preepmted on the garbages */
-       mutex_unlock(&kprobe_insn_mutex);
-       safety = check_safety();
-       mutex_lock(&kprobe_insn_mutex);
-       if (safety != 0)
+       if (check_safety())
                return -EAGAIN;
 
        hlist_for_each_entry_safe(kip, pos, next, &kprobe_insn_pages, hlist) {
index 9b1a7de26979a7d02abc5f2e68025a5acea0bdfd..eb8751aa0418d448f2b46d364074d39bf622ec6b 100644 (file)
@@ -180,10 +180,12 @@ EXPORT_SYMBOL(kthread_bind);
  * @k: thread created by kthread_create().
  *
  * Sets kthread_should_stop() for @k to return true, wakes it, and
- * waits for it to exit.  Your threadfn() must not call do_exit()
- * itself if you use this function!  This can also be called after
- * kthread_create() instead of calling wake_up_process(): the thread
- * will exit without calling threadfn().
+ * waits for it to exit. This can also be called after kthread_create()
+ * instead of calling wake_up_process(): the thread will exit without
+ * calling threadfn().
+ *
+ * If threadfn() may call do_exit() itself, the caller must ensure
+ * task_struct can't go away.
  *
  * Returns the result of threadfn(), or %-EINTR if wake_up_process()
  * was never called.
index 0a049837008e6b77d416659dfd0588fed37b00b5..fd141140355889abd13630c663e66a2e87267194 100644 (file)
@@ -1068,7 +1068,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
 {
        const unsigned long *crc;
 
-       if (!find_symbol("module_layout", NULL, &crc, true, false))
+       if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL,
+                        &crc, true, false))
                BUG();
        return check_version(sechdrs, versindex, "module_layout", mod, crc);
 }
index a641eb753b8cc92b664966e3a6932c595f07b111..9509310419545e03d015f851169436921c2fbeb3 100644 (file)
@@ -146,6 +146,28 @@ static void put_ctx(struct perf_counter_context *ctx)
        }
 }
 
+static void unclone_ctx(struct perf_counter_context *ctx)
+{
+       if (ctx->parent_ctx) {
+               put_ctx(ctx->parent_ctx);
+               ctx->parent_ctx = NULL;
+       }
+}
+
+/*
+ * If we inherit counters we want to return the parent counter id
+ * to userspace.
+ */
+static u64 primary_counter_id(struct perf_counter *counter)
+{
+       u64 id = counter->id;
+
+       if (counter->parent)
+               id = counter->parent->id;
+
+       return id;
+}
+
 /*
  * Get the perf_counter_context for a task and lock it.
  * This has to cope with with the fact that until it is locked,
@@ -1288,7 +1310,6 @@ static void perf_counter_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu)
 #define MAX_INTERRUPTS (~0ULL)
 
 static void perf_log_throttle(struct perf_counter *counter, int enable);
-static void perf_log_period(struct perf_counter *counter, u64 period);
 
 static void perf_adjust_period(struct perf_counter *counter, u64 events)
 {
@@ -1307,8 +1328,6 @@ static void perf_adjust_period(struct perf_counter *counter, u64 events)
        if (!sample_period)
                sample_period = 1;
 
-       perf_log_period(counter, sample_period);
-
        hwc->sample_period = sample_period;
 }
 
@@ -1463,10 +1482,8 @@ static void perf_counter_enable_on_exec(struct task_struct *task)
        /*
         * Unclone this context if we enabled any counter.
         */
-       if (enabled && ctx->parent_ctx) {
-               put_ctx(ctx->parent_ctx);
-               ctx->parent_ctx = NULL;
-       }
+       if (enabled)
+               unclone_ctx(ctx);
 
        spin_unlock(&ctx->lock);
 
@@ -1526,7 +1543,6 @@ __perf_counter_init_context(struct perf_counter_context *ctx,
 
 static struct perf_counter_context *find_get_context(pid_t pid, int cpu)
 {
-       struct perf_counter_context *parent_ctx;
        struct perf_counter_context *ctx;
        struct perf_cpu_context *cpuctx;
        struct task_struct *task;
@@ -1586,11 +1602,7 @@ static struct perf_counter_context *find_get_context(pid_t pid, int cpu)
  retry:
        ctx = perf_lock_task_context(task, &flags);
        if (ctx) {
-               parent_ctx = ctx->parent_ctx;
-               if (parent_ctx) {
-                       put_ctx(parent_ctx);
-                       ctx->parent_ctx = NULL;         /* no longer a clone */
-               }
+               unclone_ctx(ctx);
                spin_unlock_irqrestore(&ctx->lock, flags);
        }
 
@@ -1704,7 +1716,7 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count)
                values[n++] = counter->total_time_running +
                        atomic64_read(&counter->child_total_time_running);
        if (counter->attr.read_format & PERF_FORMAT_ID)
-               values[n++] = counter->id;
+               values[n++] = primary_counter_id(counter);
        mutex_unlock(&counter->child_mutex);
 
        if (count < n * sizeof(u64))
@@ -1811,8 +1823,6 @@ static int perf_counter_period(struct perf_counter *counter, u64 __user *arg)
 
                counter->attr.sample_freq = value;
        } else {
-               perf_log_period(counter, value);
-
                counter->attr.sample_period = value;
                counter->hw.sample_period = value;
        }
@@ -2661,10 +2671,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
        if (sample_type & PERF_SAMPLE_ID)
                header.size += sizeof(u64);
 
+       if (sample_type & PERF_SAMPLE_STREAM_ID)
+               header.size += sizeof(u64);
+
        if (sample_type & PERF_SAMPLE_CPU) {
                header.size += sizeof(cpu_entry);
 
                cpu_entry.cpu = raw_smp_processor_id();
+               cpu_entry.reserved = 0;
        }
 
        if (sample_type & PERF_SAMPLE_PERIOD)
@@ -2703,7 +2717,13 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
        if (sample_type & PERF_SAMPLE_ADDR)
                perf_output_put(&handle, data->addr);
 
-       if (sample_type & PERF_SAMPLE_ID)
+       if (sample_type & PERF_SAMPLE_ID) {
+               u64 id = primary_counter_id(counter);
+
+               perf_output_put(&handle, id);
+       }
+
+       if (sample_type & PERF_SAMPLE_STREAM_ID)
                perf_output_put(&handle, counter->id);
 
        if (sample_type & PERF_SAMPLE_CPU)
@@ -2726,7 +2746,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                        if (sub != counter)
                                sub->pmu->read(sub);
 
-                       group_entry.id = sub->id;
+                       group_entry.id = primary_counter_id(sub);
                        group_entry.counter = atomic64_read(&sub->count);
 
                        perf_output_put(&handle, group_entry);
@@ -2786,15 +2806,8 @@ perf_counter_read_event(struct perf_counter *counter,
        }
 
        if (counter->attr.read_format & PERF_FORMAT_ID) {
-               u64 id;
-
                event.header.size += sizeof(u64);
-               if (counter->parent)
-                       id = counter->parent->id;
-               else
-                       id = counter->id;
-
-               event.format[i++] = id;
+               event.format[i++] = primary_counter_id(counter);
        }
 
        ret = perf_output_begin(&handle, counter, event.header.size, 0, 0);
@@ -2895,8 +2908,11 @@ void perf_counter_fork(struct task_struct *task)
                .event  = {
                        .header = {
                                .type = PERF_EVENT_FORK,
+                               .misc = 0,
                                .size = sizeof(fork_event.event),
                        },
+                       /* .pid  */
+                       /* .ppid */
                },
        };
 
@@ -2968,8 +2984,10 @@ static void perf_counter_comm_event(struct perf_comm_event *comm_event)
        struct perf_cpu_context *cpuctx;
        struct perf_counter_context *ctx;
        unsigned int size;
-       char *comm = comm_event->task->comm;
+       char comm[TASK_COMM_LEN];
 
+       memset(comm, 0, sizeof(comm));
+       strncpy(comm, comm_event->task->comm, sizeof(comm));
        size = ALIGN(strlen(comm)+1, sizeof(u64));
 
        comm_event->comm = comm;
@@ -3004,8 +3022,16 @@ void perf_counter_comm(struct task_struct *task)
 
        comm_event = (struct perf_comm_event){
                .task   = task,
+               /* .comm      */
+               /* .comm_size */
                .event  = {
-                       .header = { .type = PERF_EVENT_COMM, },
+                       .header = {
+                               .type = PERF_EVENT_COMM,
+                               .misc = 0,
+                               /* .size */
+                       },
+                       /* .pid */
+                       /* .tid */
                },
        };
 
@@ -3088,8 +3114,15 @@ static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event)
        char *buf = NULL;
        const char *name;
 
+       memset(tmp, 0, sizeof(tmp));
+
        if (file) {
-               buf = kzalloc(PATH_MAX, GFP_KERNEL);
+               /*
+                * d_path works from the end of the buffer backwards, so we
+                * need to add enough zero bytes after the string to handle
+                * the 64bit alignment we do later.
+                */
+               buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL);
                if (!buf) {
                        name = strncpy(tmp, "//enomem", sizeof(tmp));
                        goto got_name;
@@ -3100,9 +3133,11 @@ static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event)
                        goto got_name;
                }
        } else {
-               name = arch_vma_name(mmap_event->vma);
-               if (name)
+               if (arch_vma_name(mmap_event->vma)) {
+                       name = strncpy(tmp, arch_vma_name(mmap_event->vma),
+                                      sizeof(tmp));
                        goto got_name;
+               }
 
                if (!vma->vm_mm) {
                        name = strncpy(tmp, "[vdso]", sizeof(tmp));
@@ -3147,8 +3182,16 @@ void __perf_counter_mmap(struct vm_area_struct *vma)
 
        mmap_event = (struct perf_mmap_event){
                .vma    = vma,
+               /* .file_name */
+               /* .file_size */
                .event  = {
-                       .header = { .type = PERF_EVENT_MMAP, },
+                       .header = {
+                               .type = PERF_EVENT_MMAP,
+                               .misc = 0,
+                               /* .size */
+                       },
+                       /* .pid */
+                       /* .tid */
                        .start  = vma->vm_start,
                        .len    = vma->vm_end - vma->vm_start,
                        .pgoff  = vma->vm_pgoff,
@@ -3158,49 +3201,6 @@ void __perf_counter_mmap(struct vm_area_struct *vma)
        perf_counter_mmap_event(&mmap_event);
 }
 
-/*
- * Log sample_period changes so that analyzing tools can re-normalize the
- * event flow.
- */
-
-struct freq_event {
-       struct perf_event_header        header;
-       u64                             time;
-       u64                             id;
-       u64                             period;
-};
-
-static void perf_log_period(struct perf_counter *counter, u64 period)
-{
-       struct perf_output_handle handle;
-       struct freq_event event;
-       int ret;
-
-       if (counter->hw.sample_period == period)
-               return;
-
-       if (counter->attr.sample_type & PERF_SAMPLE_PERIOD)
-               return;
-
-       event = (struct freq_event) {
-               .header = {
-                       .type = PERF_EVENT_PERIOD,
-                       .misc = 0,
-                       .size = sizeof(event),
-               },
-               .time = sched_clock(),
-               .id = counter->id,
-               .period = period,
-       };
-
-       ret = perf_output_begin(&handle, counter, sizeof(event), 1, 0);
-       if (ret)
-               return;
-
-       perf_output_put(&handle, event);
-       perf_output_end(&handle);
-}
-
 /*
  * IRQ throttle logging
  */
@@ -3214,16 +3214,21 @@ static void perf_log_throttle(struct perf_counter *counter, int enable)
                struct perf_event_header        header;
                u64                             time;
                u64                             id;
+               u64                             stream_id;
        } throttle_event = {
                .header = {
-                       .type = PERF_EVENT_THROTTLE + 1,
+                       .type = PERF_EVENT_THROTTLE,
                        .misc = 0,
                        .size = sizeof(throttle_event),
                },
-               .time   = sched_clock(),
-               .id     = counter->id,
+               .time           = sched_clock(),
+               .id             = primary_counter_id(counter),
+               .stream_id      = counter->id,
        };
 
+       if (enable)
+               throttle_event.header.type = PERF_EVENT_UNTHROTTLE;
+
        ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0);
        if (ret)
                return;
@@ -3671,7 +3676,7 @@ static const struct pmu perf_ops_task_clock = {
 void perf_tpcounter_event(int event_id)
 {
        struct perf_sample_data data = {
-               .regs = get_irq_regs();
+               .regs = get_irq_regs(),
                .addr = 0,
        };
 
@@ -3687,16 +3692,12 @@ extern void ftrace_profile_disable(int);
 
 static void tp_perf_counter_destroy(struct perf_counter *counter)
 {
-       ftrace_profile_disable(perf_event_id(&counter->attr));
+       ftrace_profile_disable(counter->attr.config);
 }
 
 static const struct pmu *tp_perf_counter_init(struct perf_counter *counter)
 {
-       int event_id = perf_event_id(&counter->attr);
-       int ret;
-
-       ret = ftrace_profile_enable(event_id);
-       if (ret)
+       if (ftrace_profile_enable(counter->attr.config))
                return NULL;
 
        counter->destroy = tp_perf_counter_destroy;
@@ -4255,15 +4256,12 @@ void perf_counter_exit_task(struct task_struct *child)
         */
        spin_lock(&child_ctx->lock);
        child->perf_counter_ctxp = NULL;
-       if (child_ctx->parent_ctx) {
-               /*
-                * This context is a clone; unclone it so it can't get
-                * swapped to another process while we're removing all
-                * the counters from it.
-                */
-               put_ctx(child_ctx->parent_ctx);
-               child_ctx->parent_ctx = NULL;
-       }
+       /*
+        * If this context is a clone; unclone it so it can't get
+        * swapped to another process while we're removing all
+        * the counters from it.
+        */
+       unclone_ctx(child_ctx);
        spin_unlock(&child_ctx->lock);
        local_irq_restore(flags);
 
index 5fa1db48d8b70c686462fc7315b833efe503d101..31310b5d3f50325ed75a6e54b94fc715d63698fa 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/pid_namespace.h>
 #include <linux/init_task.h>
 #include <linux/syscalls.h>
-#include <linux/kmemleak.h>
 
 #define pid_hashfn(nr, ns)     \
        hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)
@@ -513,12 +512,6 @@ void __init pidhash_init(void)
        pid_hash = alloc_bootmem(pidhash_size * sizeof(*(pid_hash)));
        if (!pid_hash)
                panic("Could not alloc pidhash!\n");
-       /*
-        * pid_hash contains references to allocated struct pid objects and it
-        * must be scanned by kmemleak to avoid false positives.
-        */
-       kmemleak_alloc(pid_hash, pidhash_size * sizeof(*(pid_hash)), 0,
-                      GFP_KERNEL);
        for (i = 0; i < pidhash_size; i++)
                INIT_HLIST_HEAD(&pid_hash[i]);
 }
index ed97375daae9326ecf2b4864ff9368f1491f642a..bf0014d6a5f0972a1b2352d35a09eb82296164d1 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
-#include <linux/smp_lock.h>
 #include <scsi/scsi_scan.h>
 
 #include <asm/uaccess.h>
index 0dccfbba6d267ad59b62314d665a3a91b3104252..7717b95c202782d2af38837fc09dc475a5f845bb 100644 (file)
@@ -1533,7 +1533,7 @@ void __init __rcu_init(void)
        int j;
        struct rcu_node *rnp;
 
-       printk(KERN_WARNING "Experimental hierarchical RCU implementation.\n");
+       printk(KERN_INFO "Hierarchical RCU implementation.\n");
 #ifdef CONFIG_RCU_CPU_STALL_DETECTOR
        printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
@@ -1546,7 +1546,6 @@ void __init __rcu_init(void)
                rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i);
        /* Register notifier for non-boot CPUs */
        register_cpu_notifier(&rcu_nb);
-       printk(KERN_WARNING "Experimental hierarchical RCU init done.\n");
 }
 
 module_param(blimit, int, 0);
index 7c9098d186e6f8e398c0cb9500c1efa2120293e2..1b59e265273b032d6aac2baec9b059646ca563bf 100644 (file)
@@ -493,6 +493,7 @@ struct rt_rq {
 #endif
 #ifdef CONFIG_SMP
        unsigned long rt_nr_migratory;
+       unsigned long rt_nr_total;
        int overloaded;
        struct plist_head pushable_tasks;
 #endif
@@ -2571,15 +2572,37 @@ static void __sched_fork(struct task_struct *p)
        p->se.avg_wakeup                = sysctl_sched_wakeup_granularity;
 
 #ifdef CONFIG_SCHEDSTATS
-       p->se.wait_start                = 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_start                        = 0;
+       p->se.wait_max                          = 0;
+       p->se.wait_count                        = 0;
+       p->se.wait_sum                          = 0;
+
+       p->se.sleep_start                       = 0;
+       p->se.sleep_max                         = 0;
+       p->se.sum_sleep_runtime                 = 0;
+
+       p->se.block_start                       = 0;
+       p->se.block_max                         = 0;
+       p->se.exec_max                          = 0;
+       p->se.slice_max                         = 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;
+
 #endif
 
        INIT_LIST_HEAD(&p->rt.run_list);
@@ -6541,6 +6564,11 @@ SYSCALL_DEFINE0(sched_yield)
        return 0;
 }
 
+static inline int should_resched(void)
+{
+       return need_resched() && !(preempt_count() & PREEMPT_ACTIVE);
+}
+
 static void __cond_resched(void)
 {
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
@@ -6560,8 +6588,7 @@ static void __cond_resched(void)
 
 int __sched _cond_resched(void)
 {
-       if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) &&
-                                       system_state == SYSTEM_RUNNING) {
+       if (should_resched()) {
                __cond_resched();
                return 1;
        }
@@ -6579,12 +6606,12 @@ EXPORT_SYMBOL(_cond_resched);
  */
 int cond_resched_lock(spinlock_t *lock)
 {
-       int resched = need_resched() && system_state == SYSTEM_RUNNING;
+       int resched = should_resched();
        int ret = 0;
 
        if (spin_needbreak(lock) || resched) {
                spin_unlock(lock);
-               if (resched && need_resched())
+               if (resched)
                        __cond_resched();
                else
                        cpu_relax();
@@ -6599,7 +6626,7 @@ int __sched cond_resched_softirq(void)
 {
        BUG_ON(!in_softirq());
 
-       if (need_resched() && system_state == SYSTEM_RUNNING) {
+       if (should_resched()) {
                local_bh_enable();
                __cond_resched();
                local_bh_disable();
@@ -7262,6 +7289,7 @@ static void migrate_dead_tasks(unsigned int dead_cpu)
 static void calc_global_load_remove(struct rq *rq)
 {
        atomic_long_sub(rq->calc_load_active, &calc_load_tasks);
+       rq->calc_load_active = 0;
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -7488,6 +7516,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                task_rq_unlock(rq, &flags);
                get_task_struct(p);
                cpu_rq(cpu)->migration_thread = p;
+               rq->calc_load_update = calc_load_update;
                break;
 
        case CPU_ONLINE:
@@ -7498,8 +7527,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                /* Update our root-domain */
                rq = cpu_rq(cpu);
                spin_lock_irqsave(&rq->lock, flags);
-               rq->calc_load_update = calc_load_update;
-               rq->calc_load_active = 0;
                if (rq->rd) {
                        BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
 
@@ -9070,7 +9097,7 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
 #ifdef CONFIG_SMP
        rt_rq->rt_nr_migratory = 0;
        rt_rq->overloaded = 0;
-       plist_head_init(&rq->rt.pushable_tasks, &rq->lock);
+       plist_head_init(&rt_rq->pushable_tasks, &rq->lock);
 #endif
 
        rt_rq->rt_time = 0;
index ba7fd6e9556f892dd941ecdd9e77be225929c251..9ffb2b2ceba484145b7e2f2a260c311c7eb32921 100644 (file)
@@ -266,6 +266,12 @@ static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
        return min_vruntime;
 }
 
+static inline int entity_before(struct sched_entity *a,
+                               struct sched_entity *b)
+{
+       return (s64)(a->vruntime - b->vruntime) < 0;
+}
+
 static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
        return se->vruntime - cfs_rq->min_vruntime;
@@ -687,7 +693,8 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
                         * all of which have the same weight.
                         */
                        if (sched_feat(NORMALIZED_SLEEPER) &&
-                                       task_of(se)->policy != SCHED_IDLE)
+                                       (!entity_is_task(se) ||
+                                        task_of(se)->policy != SCHED_IDLE))
                                thresh = calc_delta_fair(thresh, se);
 
                        vruntime -= thresh;
@@ -1016,7 +1023,7 @@ static void yield_task_fair(struct rq *rq)
        /*
         * Already in the rightmost position?
         */
-       if (unlikely(!rightmost || rightmost->vruntime < se->vruntime))
+       if (unlikely(!rightmost || entity_before(rightmost, se)))
                return;
 
        /*
@@ -1712,7 +1719,7 @@ static void task_new_fair(struct rq *rq, struct task_struct *p)
 
        /* 'curr' will be NULL if the child belongs to a different group */
        if (sysctl_sched_child_runs_first && this_cpu == task_cpu(p) &&
-                       curr && curr->vruntime < se->vruntime) {
+                       curr && entity_before(curr, se)) {
                /*
                 * Upon rescheduling, sched_class::put_prev_task() will place
                 * 'current' within the tree based on its new key value.
index 9bf0d2a7304569a87ba4aa0c919bbb2531c39c06..3918e01994e0a92bd734d22eebef7047e0a17a57 100644 (file)
@@ -10,6 +10,8 @@ static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se)
 
 #ifdef CONFIG_RT_GROUP_SCHED
 
+#define rt_entity_is_task(rt_se) (!(rt_se)->my_q)
+
 static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
 {
        return rt_rq->rq;
@@ -22,6 +24,8 @@ static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
 
 #else /* CONFIG_RT_GROUP_SCHED */
 
+#define rt_entity_is_task(rt_se) (1)
+
 static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
 {
        return container_of(rt_rq, struct rq, rt);
@@ -73,7 +77,7 @@ static inline void rt_clear_overload(struct rq *rq)
 
 static void update_rt_migration(struct rt_rq *rt_rq)
 {
-       if (rt_rq->rt_nr_migratory && (rt_rq->rt_nr_running > 1)) {
+       if (rt_rq->rt_nr_migratory && rt_rq->rt_nr_total > 1) {
                if (!rt_rq->overloaded) {
                        rt_set_overload(rq_of_rt_rq(rt_rq));
                        rt_rq->overloaded = 1;
@@ -86,6 +90,12 @@ static void update_rt_migration(struct rt_rq *rt_rq)
 
 static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 {
+       if (!rt_entity_is_task(rt_se))
+               return;
+
+       rt_rq = &rq_of_rt_rq(rt_rq)->rt;
+
+       rt_rq->rt_nr_total++;
        if (rt_se->nr_cpus_allowed > 1)
                rt_rq->rt_nr_migratory++;
 
@@ -94,6 +104,12 @@ static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 
 static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 {
+       if (!rt_entity_is_task(rt_se))
+               return;
+
+       rt_rq = &rq_of_rt_rq(rt_rq)->rt;
+
+       rt_rq->rt_nr_total--;
        if (rt_se->nr_cpus_allowed > 1)
                rt_rq->rt_nr_migratory--;
 
index 3a94905fa5d27c4d0ef59ad56e83ad353e14f1fa..eb5e131a048528163c01930a413db3b4676e5c7c 100644 (file)
@@ -345,7 +345,9 @@ void open_softirq(int nr, void (*action)(struct softirq_action *))
        softirq_vec[nr].action = action;
 }
 
-/* Tasklets */
+/*
+ * Tasklets
+ */
 struct tasklet_head
 {
        struct tasklet_struct *head;
@@ -493,6 +495,66 @@ void tasklet_kill(struct tasklet_struct *t)
 
 EXPORT_SYMBOL(tasklet_kill);
 
+/*
+ * tasklet_hrtimer
+ */
+
+/*
+ * The trampoline is called when the hrtimer expires. If this is
+ * called from the hrtimer interrupt then we schedule the tasklet as
+ * the timer callback function expects to run in softirq context. If
+ * it's called in softirq context anyway (i.e. high resolution timers
+ * disabled) then the hrtimer callback is called right away.
+ */
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+       struct tasklet_hrtimer *ttimer =
+               container_of(timer, struct tasklet_hrtimer, timer);
+
+       if (hrtimer_is_hres_active(timer)) {
+               tasklet_hi_schedule(&ttimer->tasklet);
+               return HRTIMER_NORESTART;
+       }
+       return ttimer->function(timer);
+}
+
+/*
+ * Helper function which calls the hrtimer callback from
+ * tasklet/softirq context
+ */
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+       struct tasklet_hrtimer *ttimer = (void *)data;
+       enum hrtimer_restart restart;
+
+       restart = ttimer->function(&ttimer->timer);
+       if (restart != HRTIMER_NORESTART)
+               hrtimer_restart(&ttimer->timer);
+}
+
+/**
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
+ * @ttimer:     tasklet_hrtimer which is initialized
+ * @function:   hrtimer callback funtion which gets called from softirq context
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
+ * @mode:       hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
+ */
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+                         enum hrtimer_restart (*function)(struct hrtimer *),
+                         clockid_t which_clock, enum hrtimer_mode mode)
+{
+       hrtimer_init(&ttimer->timer, which_clock, mode);
+       ttimer->timer.function = __hrtimer_tasklet_trampoline;
+       tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+                    (unsigned long)ttimer);
+       ttimer->function = function;
+}
+EXPORT_SYMBOL_GPL(tasklet_hrtimer_init);
+
+/*
+ * Remote softirq bits
+ */
+
 DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
 EXPORT_PER_CPU_SYMBOL(softirq_work_list);
 
index 1ad6dd46111920d10c5d83f2f90c1aeeb81ca66d..a6dcd67b041d200fc61f2b2de06890e8a5c65443 100644 (file)
@@ -254,15 +254,4 @@ void clockevents_notify(unsigned long reason, void *arg)
        spin_unlock(&clockevents_lock);
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
-
-ktime_t clockevents_get_next_event(int cpu)
-{
-       struct tick_device *td;
-       struct clock_event_device *dev;
-
-       td = &per_cpu(tick_cpu_device, cpu);
-       dev = td->evtdev;
-
-       return dev->next_event;
-}
 #endif
index 592bf584d1d2b5fa86a7fb605e4f5cf2901eda11..7466cb8112517b3bbc8869e4c2c91438ee74608c 100644 (file)
@@ -513,7 +513,7 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev,
         * Check to make sure we don't switch to a non-highres capable
         * clocksource if the tick code is in oneshot mode (highres or nohz)
         */
-       if (tick_oneshot_mode_active() &&
+       if (tick_oneshot_mode_active() && ovr &&
            !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) {
                printk(KERN_WARNING "%s clocksource is not HRT compatible. "
                        "Cannot switch while in HRT/NOHZ mode\n", ovr->name);
index 0b36b9e5cc8b4e27f6adf89de403885cfe8a6687..a7f07d5a6241d882af4466ec3280a89f2681e8c9 100644 (file)
@@ -714,7 +714,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
         * networking code - if the timer is re-modified
         * to be the same thing then just return:
         */
-       if (timer->expires == expires && timer_pending(timer))
+       if (timer_pending(timer) && timer->expires == expires)
                return 1;
 
        return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
index 1551f47e7669ba06f5e010410e9408cb9de07eb4..019f380fd764c80354ed277cfc72b7a2e4906b19 100644 (file)
@@ -226,13 +226,13 @@ config BOOT_TRACER
          the timings of the initcalls and traces key events and the identity
          of tasks that can cause boot delays, such as context-switches.
 
-         Its aim is to be parsed by the /scripts/bootgraph.pl tool to
+         Its aim is to be parsed by the scripts/bootgraph.pl tool to
          produce pretty graphics about boot inefficiencies, giving a visual
          representation of the delays during initcalls - but the raw
          /debug/tracing/trace text output is readable too.
 
-         You must pass in ftrace=initcall to the kernel command line
-         to enable this on bootup.
+         You must pass in initcall_debug and ftrace=initcall to the kernel
+         command line to enable this on bootup.
 
 config TRACE_BRANCH_PROFILING
        bool
index 39af8af6fc302c981226ab8c8f277026b319ca4a..1090b0aed9bac6135d359e0cb07317085e6145d6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
+#include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/uaccess.h>
 
index f3716bf04df648418b5f8dc246d54c958097baaf..4521c77d1a1aff64419d0afb0d6b84906c306454 100644 (file)
@@ -768,7 +768,7 @@ static struct tracer_stat function_stats __initdata = {
        .stat_show      = function_stat_show
 };
 
-static void ftrace_profile_debugfs(struct dentry *d_tracer)
+static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 {
        struct ftrace_profile_stat *stat;
        struct dentry *entry;
@@ -786,7 +786,6 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer)
                         * The files created are permanent, if something happens
                         * we still do not free memory.
                         */
-                       kfree(stat);
                        WARN(1,
                             "Could not allocate stat file for cpu %d\n",
                             cpu);
@@ -813,7 +812,7 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer)
 }
 
 #else /* CONFIG_FUNCTION_PROFILER */
-static void ftrace_profile_debugfs(struct dentry *d_tracer)
+static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 {
 }
 #endif /* CONFIG_FUNCTION_PROFILER */
@@ -3160,10 +3159,10 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
        ret  = proc_dointvec(table, write, file, buffer, lenp, ppos);
 
-       if (ret || !write || (last_ftrace_enabled == ftrace_enabled))
+       if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled))
                goto out;
 
-       last_ftrace_enabled = ftrace_enabled;
+       last_ftrace_enabled = !!ftrace_enabled;
 
        if (ftrace_enabled) {
 
index 3aa0a0dfdfa818ccada26954797f6e933b592222..8bc8d8afea6acd9f6dca1131dcd6b8ca3e2084d8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/writeback.h>
 #include <linux/kallsyms.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/irqflags.h>
 #include <linux/debugfs.h>
index 5e32e375134d976183bb0ae5df79abda3f029a54..6db005e12487cd943fb23d3978f4be71ce3cf9ec 100644 (file)
@@ -26,6 +26,9 @@ TRACE_EVENT_FORMAT(funcgraph_exit, TRACE_GRAPH_RET,
                   ftrace_graph_ret_entry, ignore,
        TRACE_STRUCT(
                TRACE_FIELD(unsigned long, ret.func, func)
+               TRACE_FIELD(unsigned long long, ret.calltime, calltime)
+               TRACE_FIELD(unsigned long long, ret.rettime, rettime)
+               TRACE_FIELD(unsigned long, ret.overrun, overrun)
                TRACE_FIELD(int, ret.depth, depth)
        ),
        TP_RAW_FMT("<-- %lx (%d)")
index 7402144bff218ddcb51a9bd7cad8c6948a481651..75ef000613c35db5c7cb8ae71b2f4169f0bfd6d8 100644 (file)
@@ -363,7 +363,7 @@ ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
  out_reg:
        ret = register_ftrace_function_probe(glob, ops, count);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
 static struct ftrace_func_command ftrace_traceon_cmd = {
index 7938f3ae93e3dbe9d898e037c47027c4908a8d94..e0c2545622e8f7617b3e32bcb8c3df235aa3a929 100644 (file)
@@ -27,8 +27,7 @@ void trace_print_seq(struct seq_file *m, struct trace_seq *s)
 {
        int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
 
-       s->buffer[len] = 0;
-       seq_puts(m, s->buffer);
+       seq_write(m, s->buffer, len);
 
        trace_seq_init(s);
 }
index 2d7aebd71dbd4e3489b8bf59fd29585b422be8e9..e644af91012468d2e8771a885d6298e0de93e66c 100644 (file)
@@ -326,10 +326,10 @@ stack_trace_sysctl(struct ctl_table *table, int write,
        ret = proc_dointvec(table, write, file, buffer, lenp, ppos);
 
        if (ret || !write ||
-           (last_stack_tracer_enabled == stack_tracer_enabled))
+           (last_stack_tracer_enabled == !!stack_tracer_enabled))
                goto out;
 
-       last_stack_tracer_enabled = stack_tracer_enabled;
+       last_stack_tracer_enabled = !!stack_tracer_enabled;
 
        if (stack_tracer_enabled)
                register_ftrace_function(&trace_ops);
index 3b93129a968c73b1d6eeff421abb76b38bc668dd..65b0d99b6d0aa8f7219741e731394d1514b1706e 100644 (file)
@@ -716,7 +716,7 @@ void dma_debug_init(u32 num_entries)
 
        for (i = 0; i < HASH_SIZE; ++i) {
                INIT_LIST_HEAD(&dma_entry_hash[i].list);
-               dma_entry_hash[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&dma_entry_hash[i].lock);
        }
 
        if (dma_debug_fs_init() != 0) {
@@ -856,22 +856,21 @@ static void check_for_stack(struct device *dev, void *addr)
                                "stack [addr=%p]\n", addr);
 }
 
-static inline bool overlap(void *addr, u64 size, void *start, void *end)
+static inline bool overlap(void *addr, unsigned long len, void *start, void *end)
 {
-       void *addr2 = (char *)addr + size;
+       unsigned long a1 = (unsigned long)addr;
+       unsigned long b1 = a1 + len;
+       unsigned long a2 = (unsigned long)start;
+       unsigned long b2 = (unsigned long)end;
 
-       return ((addr >= start && addr < end) ||
-               (addr2 >= start && addr2 < end) ||
-               ((addr < start) && (addr2 >= end)));
+       return !(b1 <= a2 || a1 >= b2);
 }
 
-static void check_for_illegal_area(struct device *dev, void *addr, u64 size)
+static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
 {
-       if (overlap(addr, size, _text, _etext) ||
-           overlap(addr, size, __start_rodata, __end_rodata))
-               err_printk(dev, NULL, "DMA-API: device driver maps "
-                               "memory from kernel text or rodata "
-                               "[addr=%p] [size=%llu]\n", addr, size);
+       if (overlap(addr, len, _text, _etext) ||
+           overlap(addr, len, __start_rodata, __end_rodata))
+               err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
 }
 
 static void check_sync(struct device *dev,
@@ -969,7 +968,8 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
                entry->type = dma_debug_single;
 
        if (!PageHighMem(page)) {
-               void *addr = ((char *)page_address(page)) + offset;
+               void *addr = page_address(page) + offset;
+
                check_for_stack(dev, addr);
                check_for_illegal_area(dev, addr, size);
        }
index 833139ce1e225cc1bef2286b3e04d2133219f8ef..e22c148e4b7fff7605e605689561df66d018c6fa 100644 (file)
@@ -164,7 +164,7 @@ static void ddebug_change(const struct ddebug_query *query,
 
                        if (!newflags)
                                dt->num_enabled--;
-                       else if (!dp-flags)
+                       else if (!dp->flags)
                                dt->num_enabled++;
                        dp->flags = newflags;
                        if (newflags) {
index 493b468a503541fd65b64872eece6fb7228e36fa..c86edd2442944ec2532bdde3e2087b56519a224d 100644 (file)
@@ -283,7 +283,6 @@ static wait_queue_head_t congestion_wqh[2] = {
                __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
        };
 
-
 void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
 {
        enum bdi_state bit;
@@ -308,18 +307,18 @@ EXPORT_SYMBOL(set_bdi_congested);
 
 /**
  * congestion_wait - wait for a backing_dev to become uncongested
- * @rw: READ or WRITE
+ * @sync: SYNC or ASYNC IO
  * @timeout: timeout in jiffies
  *
  * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit
  * write congestion.  If no backing_devs are congested then just wait for the
  * next write to be completed.
  */
-long congestion_wait(int rw, long timeout)
+long congestion_wait(int sync, long timeout)
 {
        long ret;
        DEFINE_WAIT(wait);
-       wait_queue_head_t *wqh = &congestion_wqh[rw];
+       wait_queue_head_t *wqh = &congestion_wqh[sync];
 
        prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
        ret = io_schedule_timeout(timeout);
index d2a9ce952768fbcb88f559077d9878cb15e1d03c..701740c9e81bdf967062b340e53cff8b7913427a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pfn.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/kmemleak.h>
 
 #include <asm/bug.h>
 #include <asm/io.h>
@@ -335,6 +336,8 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
 {
        unsigned long start, end;
 
+       kmemleak_free_part(__va(physaddr), size);
+
        start = PFN_UP(physaddr);
        end = PFN_DOWN(physaddr + size);
 
@@ -354,6 +357,8 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
 {
        unsigned long start, end;
 
+       kmemleak_free_part(__va(addr), size);
+
        start = PFN_UP(addr);
        end = PFN_DOWN(addr + size);
 
@@ -516,6 +521,7 @@ find_block:
                region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
                                start_off);
                memset(region, 0, size);
+               kmemleak_alloc(region, size, 1, 0);
                return region;
        }
 
index e766e1da09d2880ea9db6f07fd869e9c758f8d3b..5aabd41ffb8fafbea9fd3a507d9ac5ef6a679e25 100644 (file)
  * Kmemleak configuration and common defines.
  */
 #define MAX_TRACE              16      /* stack trace length */
-#define REPORTS_NR             50      /* maximum number of reported leaks */
 #define MSECS_MIN_AGE          5000    /* minimum object age for reporting */
 #define SECS_FIRST_SCAN                60      /* delay before the first scan */
 #define SECS_SCAN_WAIT         600     /* subsequent auto scanning delay */
+#define GRAY_LIST_PASSES       25      /* maximum number of gray list scans */
 
 #define BYTES_PER_POINTER      sizeof(void *)
 
@@ -158,6 +158,8 @@ struct kmemleak_object {
 #define OBJECT_REPORTED                (1 << 1)
 /* flag set to not scan the object */
 #define OBJECT_NO_SCAN         (1 << 2)
+/* flag set on newly allocated objects */
+#define OBJECT_NEW             (1 << 3)
 
 /* the list of all allocated objects */
 static LIST_HEAD(object_list);
@@ -196,9 +198,6 @@ static int kmemleak_stack_scan = 1;
 /* protects the memory scanning, parameters and debug/kmemleak file access */
 static DEFINE_MUTEX(scan_mutex);
 
-/* number of leaks reported (for limitation purposes) */
-static int reported_leaks;
-
 /*
  * Early object allocation/freeing logging. Kmemleak is initialized after the
  * kernel allocator. However, both the kernel allocator and kmemleak may
@@ -211,6 +210,7 @@ static int reported_leaks;
 enum {
        KMEMLEAK_ALLOC,
        KMEMLEAK_FREE,
+       KMEMLEAK_FREE_PART,
        KMEMLEAK_NOT_LEAK,
        KMEMLEAK_IGNORE,
        KMEMLEAK_SCAN_AREA,
@@ -274,6 +274,11 @@ static int color_gray(const struct kmemleak_object *object)
        return object->min_count != -1 && object->count >= object->min_count;
 }
 
+static int color_black(const struct kmemleak_object *object)
+{
+       return object->min_count == -1;
+}
+
 /*
  * Objects are considered unreferenced only if their color is white, they have
  * not be deleted and have a minimum age to avoid false positives caused by
@@ -451,7 +456,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
        INIT_HLIST_HEAD(&object->area_list);
        spin_lock_init(&object->lock);
        atomic_set(&object->use_count, 1);
-       object->flags = OBJECT_ALLOCATED;
+       object->flags = OBJECT_ALLOCATED | OBJECT_NEW;
        object->pointer = ptr;
        object->size = size;
        object->min_count = min_count;
@@ -519,27 +524,17 @@ out:
  * Remove the metadata (struct kmemleak_object) for a memory block from the
  * object_list and object_tree_root and decrement its use_count.
  */
-static void delete_object(unsigned long ptr)
+static void __delete_object(struct kmemleak_object *object)
 {
        unsigned long flags;
-       struct kmemleak_object *object;
 
        write_lock_irqsave(&kmemleak_lock, flags);
-       object = lookup_object(ptr, 0);
-       if (!object) {
-#ifdef DEBUG
-               kmemleak_warn("Freeing unknown object at 0x%08lx\n",
-                             ptr);
-#endif
-               write_unlock_irqrestore(&kmemleak_lock, flags);
-               return;
-       }
        prio_tree_remove(&object_tree_root, &object->tree_node);
        list_del_rcu(&object->object_list);
        write_unlock_irqrestore(&kmemleak_lock, flags);
 
        WARN_ON(!(object->flags & OBJECT_ALLOCATED));
-       WARN_ON(atomic_read(&object->use_count) < 1);
+       WARN_ON(atomic_read(&object->use_count) < 2);
 
        /*
         * Locking here also ensures that the corresponding memory block
@@ -551,6 +546,64 @@ static void delete_object(unsigned long ptr)
        put_object(object);
 }
 
+/*
+ * Look up the metadata (struct kmemleak_object) corresponding to ptr and
+ * delete it.
+ */
+static void delete_object_full(unsigned long ptr)
+{
+       struct kmemleak_object *object;
+
+       object = find_and_get_object(ptr, 0);
+       if (!object) {
+#ifdef DEBUG
+               kmemleak_warn("Freeing unknown object at 0x%08lx\n",
+                             ptr);
+#endif
+               return;
+       }
+       __delete_object(object);
+       put_object(object);
+}
+
+/*
+ * Look up the metadata (struct kmemleak_object) corresponding to ptr and
+ * delete it. If the memory block is partially freed, the function may create
+ * additional metadata for the remaining parts of the block.
+ */
+static void delete_object_part(unsigned long ptr, size_t size)
+{
+       struct kmemleak_object *object;
+       unsigned long start, end;
+
+       object = find_and_get_object(ptr, 1);
+       if (!object) {
+#ifdef DEBUG
+               kmemleak_warn("Partially freeing unknown object at 0x%08lx "
+                             "(size %zu)\n", ptr, size);
+#endif
+               return;
+       }
+       __delete_object(object);
+
+       /*
+        * Create one or two objects that may result from the memory block
+        * split. Note that partial freeing is only done by free_bootmem() and
+        * this happens before kmemleak_init() is called. The path below is
+        * only executed during early log recording in kmemleak_init(), so
+        * GFP_KERNEL is enough.
+        */
+       start = object->pointer;
+       end = object->pointer + object->size;
+       if (ptr > start)
+               create_object(start, ptr - start, object->min_count,
+                             GFP_KERNEL);
+       if (ptr + size < end)
+               create_object(ptr + size, end - ptr - size, object->min_count,
+                             GFP_KERNEL);
+
+       put_object(object);
+}
 /*
  * Make a object permanently as gray-colored so that it can no longer be
  * reported as a leak. This is used in general to mark a false positive.
@@ -715,12 +768,27 @@ void kmemleak_free(const void *ptr)
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
-               delete_object((unsigned long)ptr);
+               delete_object_full((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
                log_early(KMEMLEAK_FREE, ptr, 0, 0, 0, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free);
 
+/*
+ * Partial memory freeing function callback. This function is usually called
+ * from bootmem allocator when (part of) a memory block is freed.
+ */
+void kmemleak_free_part(const void *ptr, size_t size)
+{
+       pr_debug("%s(0x%p)\n", __func__, ptr);
+
+       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+               delete_object_part((unsigned long)ptr, size);
+       else if (atomic_read(&kmemleak_early_log))
+               log_early(KMEMLEAK_FREE_PART, ptr, size, 0, 0, 0);
+}
+EXPORT_SYMBOL_GPL(kmemleak_free_part);
+
 /*
  * Mark an already allocated memory block as a false positive. This will cause
  * the block to no longer be reported as leak and always be scanned.
@@ -807,7 +875,7 @@ static int scan_should_stop(void)
  * found to the gray list.
  */
 static void scan_block(void *_start, void *_end,
-                      struct kmemleak_object *scanned)
+                      struct kmemleak_object *scanned, int allow_resched)
 {
        unsigned long *ptr;
        unsigned long *start = PTR_ALIGN(_start, BYTES_PER_POINTER);
@@ -818,6 +886,8 @@ static void scan_block(void *_start, void *_end,
                unsigned long pointer = *ptr;
                struct kmemleak_object *object;
 
+               if (allow_resched)
+                       cond_resched();
                if (scan_should_stop())
                        break;
 
@@ -881,12 +951,12 @@ static void scan_object(struct kmemleak_object *object)
                goto out;
        if (hlist_empty(&object->area_list))
                scan_block((void *)object->pointer,
-                          (void *)(object->pointer + object->size), object);
+                          (void *)(object->pointer + object->size), object, 0);
        else
                hlist_for_each_entry(area, elem, &object->area_list, node)
                        scan_block((void *)(object->pointer + area->offset),
                                   (void *)(object->pointer + area->offset
-                                           + area->length), object);
+                                           + area->length), object, 0);
 out:
        spin_unlock_irqrestore(&object->lock, flags);
 }
@@ -903,6 +973,7 @@ static void kmemleak_scan(void)
        struct task_struct *task;
        int i;
        int new_leaks = 0;
+       int gray_list_pass = 0;
 
        jiffies_last_scan = jiffies;
 
@@ -923,6 +994,7 @@ static void kmemleak_scan(void)
 #endif
                /* reset the reference count (whiten the object) */
                object->count = 0;
+               object->flags &= ~OBJECT_NEW;
                if (color_gray(object) && get_object(object))
                        list_add_tail(&object->gray_list, &gray_list);
 
@@ -931,14 +1003,14 @@ static void kmemleak_scan(void)
        rcu_read_unlock();
 
        /* data/bss scanning */
-       scan_block(_sdata, _edata, NULL);
-       scan_block(__bss_start, __bss_stop, NULL);
+       scan_block(_sdata, _edata, NULL, 1);
+       scan_block(__bss_start, __bss_stop, NULL, 1);
 
 #ifdef CONFIG_SMP
        /* per-cpu sections scanning */
        for_each_possible_cpu(i)
                scan_block(__per_cpu_start + per_cpu_offset(i),
-                          __per_cpu_end + per_cpu_offset(i), NULL);
+                          __per_cpu_end + per_cpu_offset(i), NULL, 1);
 #endif
 
        /*
@@ -960,7 +1032,7 @@ static void kmemleak_scan(void)
                        /* only scan if page is in use */
                        if (page_count(page) == 0)
                                continue;
-                       scan_block(page, page + 1, NULL);
+                       scan_block(page, page + 1, NULL, 1);
                }
        }
 
@@ -972,7 +1044,8 @@ static void kmemleak_scan(void)
                read_lock(&tasklist_lock);
                for_each_process(task)
                        scan_block(task_stack_page(task),
-                                  task_stack_page(task) + THREAD_SIZE, NULL);
+                                  task_stack_page(task) + THREAD_SIZE,
+                                  NULL, 0);
                read_unlock(&tasklist_lock);
        }
 
@@ -984,6 +1057,7 @@ static void kmemleak_scan(void)
         * kmemleak objects cannot be freed from outside the loop because their
         * use_count was increased.
         */
+repeat:
        object = list_entry(gray_list.next, typeof(*object), gray_list);
        while (&object->gray_list != &gray_list) {
                cond_resched();
@@ -1001,12 +1075,38 @@ static void kmemleak_scan(void)
 
                object = tmp;
        }
+
+       if (scan_should_stop() || ++gray_list_pass >= GRAY_LIST_PASSES)
+               goto scan_end;
+
+       /*
+        * Check for new objects allocated during this scanning and add them
+        * to the gray list.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(object, &object_list, object_list) {
+               spin_lock_irqsave(&object->lock, flags);
+               if ((object->flags & OBJECT_NEW) && !color_black(object) &&
+                   get_object(object)) {
+                       object->flags &= ~OBJECT_NEW;
+                       list_add_tail(&object->gray_list, &gray_list);
+               }
+               spin_unlock_irqrestore(&object->lock, flags);
+       }
+       rcu_read_unlock();
+
+       if (!list_empty(&gray_list))
+               goto repeat;
+
+scan_end:
        WARN_ON(!list_empty(&gray_list));
 
        /*
-        * If scanning was stopped do not report any new unreferenced objects.
+        * If scanning was stopped or new objects were being allocated at a
+        * higher rate than gray list scanning, do not report any new
+        * unreferenced objects.
         */
-       if (scan_should_stop())
+       if (scan_should_stop() || gray_list_pass >= GRAY_LIST_PASSES)
                return;
 
        /*
@@ -1039,6 +1139,7 @@ static int kmemleak_scan_thread(void *arg)
        static int first_run = 1;
 
        pr_info("Automatic memory scanning thread started\n");
+       set_user_nice(current, 10);
 
        /*
         * Wait before the first scan to allow the system to fully initialize.
@@ -1101,11 +1202,11 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct kmemleak_object *object;
        loff_t n = *pos;
+       int err;
 
-       if (!n)
-               reported_leaks = 0;
-       if (reported_leaks >= REPORTS_NR)
-               return NULL;
+       err = mutex_lock_interruptible(&scan_mutex);
+       if (err < 0)
+               return ERR_PTR(err);
 
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list) {
@@ -1131,8 +1232,6 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct list_head *n = &prev_obj->object_list;
 
        ++(*pos);
-       if (reported_leaks >= REPORTS_NR)
-               goto out;
 
        rcu_read_lock();
        list_for_each_continue_rcu(n, &object_list) {
@@ -1141,7 +1240,7 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                        break;
        }
        rcu_read_unlock();
-out:
+
        put_object(prev_obj);
        return next_obj;
 }
@@ -1151,8 +1250,15 @@ out:
  */
 static void kmemleak_seq_stop(struct seq_file *seq, void *v)
 {
-       if (v)
-               put_object(v);
+       if (!IS_ERR(v)) {
+               /*
+                * kmemleak_seq_start may return ERR_PTR if the scan_mutex
+                * waiting was interrupted, so only release it if !IS_ERR.
+                */
+               mutex_unlock(&scan_mutex);
+               if (v)
+                       put_object(v);
+       }
 }
 
 /*
@@ -1164,10 +1270,8 @@ static int kmemleak_seq_show(struct seq_file *seq, void *v)
        unsigned long flags;
 
        spin_lock_irqsave(&object->lock, flags);
-       if ((object->flags & OBJECT_REPORTED) && unreferenced_object(object)) {
+       if ((object->flags & OBJECT_REPORTED) && unreferenced_object(object))
                print_unreferenced(seq, object);
-               reported_leaks++;
-       }
        spin_unlock_irqrestore(&object->lock, flags);
        return 0;
 }
@@ -1181,36 +1285,15 @@ static const struct seq_operations kmemleak_seq_ops = {
 
 static int kmemleak_open(struct inode *inode, struct file *file)
 {
-       int ret = 0;
-
        if (!atomic_read(&kmemleak_enabled))
                return -EBUSY;
 
-       ret = mutex_lock_interruptible(&scan_mutex);
-       if (ret < 0)
-               goto out;
-       if (file->f_mode & FMODE_READ) {
-               ret = seq_open(file, &kmemleak_seq_ops);
-               if (ret < 0)
-                       goto scan_unlock;
-       }
-       return ret;
-
-scan_unlock:
-       mutex_unlock(&scan_mutex);
-out:
-       return ret;
+       return seq_open(file, &kmemleak_seq_ops);
 }
 
 static int kmemleak_release(struct inode *inode, struct file *file)
 {
-       int ret = 0;
-
-       if (file->f_mode & FMODE_READ)
-               seq_release(inode, file);
-       mutex_unlock(&scan_mutex);
-
-       return ret;
+       return seq_release(inode, file);
 }
 
 /*
@@ -1230,15 +1313,17 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
 {
        char buf[64];
        int buf_size;
-
-       if (!atomic_read(&kmemleak_enabled))
-               return -EBUSY;
+       int ret;
 
        buf_size = min(size, (sizeof(buf) - 1));
        if (strncpy_from_user(buf, user_buf, buf_size) < 0)
                return -EFAULT;
        buf[buf_size] = 0;
 
+       ret = mutex_lock_interruptible(&scan_mutex);
+       if (ret < 0)
+               return ret;
+
        if (strncmp(buf, "off", 3) == 0)
                kmemleak_disable();
        else if (strncmp(buf, "stack=on", 8) == 0)
@@ -1251,11 +1336,10 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                stop_scan_thread();
        else if (strncmp(buf, "scan=", 5) == 0) {
                unsigned long secs;
-               int err;
 
-               err = strict_strtoul(buf + 5, 0, &secs);
-               if (err < 0)
-                       return err;
+               ret = strict_strtoul(buf + 5, 0, &secs);
+               if (ret < 0)
+                       goto out;
                stop_scan_thread();
                if (secs) {
                        jiffies_scan_wait = msecs_to_jiffies(secs * 1000);
@@ -1264,7 +1348,12 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        } else if (strncmp(buf, "scan", 4) == 0)
                kmemleak_scan();
        else
-               return -EINVAL;
+               ret = -EINVAL;
+
+out:
+       mutex_unlock(&scan_mutex);
+       if (ret < 0)
+               return ret;
 
        /* ignore the rest of the buffer, only one command at a time */
        *ppos += size;
@@ -1293,7 +1382,7 @@ static int kmemleak_cleanup_thread(void *arg)
 
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list)
-               delete_object(object->pointer);
+               delete_object_full(object->pointer);
        rcu_read_unlock();
        mutex_unlock(&scan_mutex);
 
@@ -1388,6 +1477,9 @@ void __init kmemleak_init(void)
                case KMEMLEAK_FREE:
                        kmemleak_free(log->ptr);
                        break;
+               case KMEMLEAK_FREE_PART:
+                       kmemleak_free_part(log->ptr, log->size);
+                       break;
                case KMEMLEAK_NOT_LEAK:
                        kmemleak_not_leak(log->ptr);
                        break;
index e2fa20dadf408e2d38e6b5a4a61ed4fb9febd3a1..e717964cb5a0cc2e73ddc520a5d76d726cb6593a 100644 (file)
@@ -1973,7 +1973,7 @@ try_to_free:
                if (!progress) {
                        nr_retries--;
                        /* maybe some writeback is necessary */
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
                }
 
        }
index 65216194eb8daec69843ef672d73725eeb37e0ca..aede2ce3aba4fdf1159946cffc7b6acaf8b534d3 100644 (file)
@@ -135,11 +135,12 @@ void pmd_clear_bad(pmd_t *pmd)
  * Note: this doesn't free the actual pages themselves. That
  * has been handled earlier when unmapping all the memory regions.
  */
-static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd)
+static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
+                          unsigned long addr)
 {
        pgtable_t token = pmd_pgtable(*pmd);
        pmd_clear(pmd);
-       pte_free_tlb(tlb, token);
+       pte_free_tlb(tlb, token, addr);
        tlb->mm->nr_ptes--;
 }
 
@@ -157,7 +158,7 @@ static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
                next = pmd_addr_end(addr, end);
                if (pmd_none_or_clear_bad(pmd))
                        continue;
-               free_pte_range(tlb, pmd);
+               free_pte_range(tlb, pmd, addr);
        } while (pmd++, addr = next, addr != end);
 
        start &= PUD_MASK;
@@ -173,7 +174,7 @@ static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
 
        pmd = pmd_offset(pud, start);
        pud_clear(pud);
-       pmd_free_tlb(tlb, pmd);
+       pmd_free_tlb(tlb, pmd, start);
 }
 
 static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
@@ -206,7 +207,7 @@ static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
 
        pud = pud_offset(pgd, start);
        pgd_clear(pgd);
-       pud_free_tlb(tlb, pud);
+       pud_free_tlb(tlb, pud, start);
 }
 
 /*
index 7687879253b929e996dce647dbacab55ef91ff48..81627ebcd313fcd5ee3545a0996d2802fab36085 100644 (file)
@@ -575,7 +575,7 @@ static void balance_dirty_pages(struct address_space *mapping)
                if (pages_written >= write_chunk)
                        break;          /* We've done our duty */
 
-               congestion_wait(WRITE, HZ/10);
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
 
        if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh &&
@@ -669,7 +669,7 @@ void throttle_vm_writeout(gfp_t gfp_mask)
                 if (global_page_state(NR_UNSTABLE_NFS) +
                        global_page_state(NR_WRITEBACK) <= dirty_thresh)
                                break;
-                congestion_wait(WRITE, HZ/10);
+                congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /*
                 * The caller might hold locks which can prevent IO completion
@@ -715,7 +715,7 @@ static void background_writeout(unsigned long _min_pages)
                if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
                        /* Wrote less than expected */
                        if (wbc.encountered_congestion || wbc.more_io)
-                               congestion_wait(WRITE, HZ/10);
+                               congestion_wait(BLK_RW_ASYNC, HZ/10);
                        else
                                break;
                }
@@ -787,7 +787,7 @@ static void wb_kupdate(unsigned long arg)
                writeback_inodes(&wbc);
                if (wbc.nr_to_write > 0) {
                        if (wbc.encountered_congestion || wbc.more_io)
-                               congestion_wait(WRITE, HZ/10);
+                               congestion_wait(BLK_RW_ASYNC, HZ/10);
                        else
                                break;  /* All the old data is written */
                }
index ad7cd1c56b07c330d611a067a0749f9cabd440b0..caa92689aac951e5d6c08c89993526898bc695d1 100644 (file)
@@ -1666,7 +1666,7 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
                        preferred_zone, migratetype);
 
                if (!page && gfp_mask & __GFP_NOFAIL)
-                       congestion_wait(WRITE, HZ/50);
+                       congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (!page && (gfp_mask & __GFP_NOFAIL));
 
        return page;
@@ -1831,7 +1831,7 @@ rebalance:
        pages_reclaimed += did_some_progress;
        if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
                /* Wait for some write requests to complete then retry */
-               congestion_wait(WRITE, HZ/50);
+               congestion_wait(BLK_RW_ASYNC, HZ/50);
                goto rebalance;
        }
 
@@ -4745,8 +4745,10 @@ void *__init alloc_large_system_hash(const char *tablename,
                         * some pages at the end of hash table which
                         * alloc_pages_exact() automatically does
                         */
-                       if (get_order(size) < MAX_ORDER)
+                       if (get_order(size) < MAX_ORDER) {
                                table = alloc_pages_exact(size, GFP_ATOMIC);
+                               kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+                       }
                }
        } while (!table && size > PAGE_SIZE && --log2qty);
 
@@ -4764,16 +4766,6 @@ void *__init alloc_large_system_hash(const char *tablename,
        if (_hash_mask)
                *_hash_mask = (1 << log2qty) - 1;
 
-       /*
-        * If hashdist is set, the table allocation is done with __vmalloc()
-        * which invokes the kmemleak_alloc() callback. This function may also
-        * be called before the slab and kmemleak are initialised when
-        * kmemleak simply buffers the request to be executed later
-        * (GFP_ATOMIC flag ignored in this case).
-        */
-       if (!hashdist)
-               kmemleak_alloc(table, size, 1, GFP_ATOMIC);
-
        return table;
 }
 
index a9201d83178b8d47d38897ff44814225e37b3102..b9f1491a58a184e80769fc541d3d2958cb4919ed 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -21,7 +21,6 @@
 #include <linux/kmemcheck.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
-#include <linux/kmemleak.h>
 #include <linux/mempolicy.h>
 #include <linux/ctype.h>
 #include <linux/debugobjects.h>
@@ -2835,13 +2834,15 @@ EXPORT_SYMBOL(__kmalloc);
 static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
 {
        struct page *page;
+       void *ptr = NULL;
 
        flags |= __GFP_COMP | __GFP_NOTRACK;
        page = alloc_pages_node(node, flags, get_order(size));
        if (page)
-               return page_address(page);
-       else
-               return NULL;
+               ptr = page_address(page);
+
+       kmemleak_alloc(ptr, size, 1, flags);
+       return ptr;
 }
 
 #ifdef CONFIG_NUMA
@@ -2926,6 +2927,7 @@ void kfree(const void *x)
        page = virt_to_head_page(x);
        if (unlikely(!PageSlab(page))) {
                BUG_ON(!PageCompound(page));
+               kmemleak_free(x);
                put_page(page);
                return;
        }
index 54155268dfcae49634dc016bb168845600a866a0..dea7abd310980daea1fa6c5a0c850a972fe37a21 100644 (file)
@@ -1104,7 +1104,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                 */
                if (nr_freed < nr_taken && !current_is_kswapd() &&
                    lumpy_reclaim) {
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                        /*
                         * The attempt at page out may have made some
@@ -1721,7 +1721,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
 
                /* Take a nap, wait for some writeback to complete */
                if (sc->nr_scanned && priority < DEF_PRIORITY - 2)
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
        /* top priority shrink_zones still had more to do? don't OOM, then */
        if (!sc->all_unreclaimable && scanning_global_lru(sc))
@@ -1960,7 +1960,7 @@ loop_again:
                 * another pass across the zones.
                 */
                if (total_scanned && priority < DEF_PRIORITY - 2)
-                       congestion_wait(WRITE, HZ/10);
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                /*
                 * We do this so kswapd doesn't build up large priorities for
@@ -2233,7 +2233,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                                goto out;
 
                        if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
-                               congestion_wait(WRITE, HZ / 10);
+                               congestion_wait(BLK_RW_ASYNC, HZ / 10);
                }
        }
 
index dd43a8289b0d9ecaf74aadc205063d2e2eaf8b3a..787ccddb85ea6cd8c53550deef5a11e3336a4ee1 100644 (file)
@@ -117,9 +117,6 @@ static int parse_opts(char *opts, struct p9_client *clnt)
                }
        }
 
-       if (!clnt->trans_mod)
-               clnt->trans_mod = v9fs_get_default_trans();
-
        kfree(options);
        return ret;
 }
@@ -689,6 +686,9 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
        if (err < 0)
                goto error;
 
+       if (!clnt->trans_mod)
+               clnt->trans_mod = v9fs_get_default_trans();
+
        if (clnt->trans_mod == NULL) {
                err = -EPROTONOSUPPORT;
                P9_DPRINTK(P9_DEBUG_ERROR,
@@ -1098,7 +1098,6 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
 
        if (data) {
                memmove(data, dataptr, count);
-               data += count;
        }
 
        if (udata) {
@@ -1192,9 +1191,9 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
 
        err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret);
        if (err) {
-               ret = ERR_PTR(err);
                p9pdu_dump(1, req->rc);
-               goto free_and_error;
+               p9_free_req(clnt, req);
+               goto error;
        }
 
        P9_DPRINTK(P9_DEBUG_9P,
@@ -1211,8 +1210,6 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
        p9_free_req(clnt, req);
        return ret;
 
-free_and_error:
-       p9_free_req(clnt, req);
 error:
        kfree(ret);
        return ERR_PTR(err);
index 590b8396362237e62b82965b2f6e95fb1c167591..bfbe13786bb468acfeedb888e8ee4a209c34b2e2 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/if_arp.h>
+#include <linux/smp_lock.h>
 #include <linux/termios.h>     /* For TIOCOUTQ/INQ */
 #include <net/datalink.h>
 #include <net/psnap.h>
index c1c97936192c730d8f68431a782f8695c43504a3..8c4d843eb17f46bbec50847aa1352580adcd1c26 100644 (file)
@@ -92,7 +92,7 @@ static void vcc_sock_destruct(struct sock *sk)
 static void vcc_def_wakeup(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up(sk->sk_sleep);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -110,7 +110,7 @@ static void vcc_write_space(struct sock *sk)
        read_lock(&sk->sk_callback_lock);
 
        if (vcc_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible(sk->sk_sleep);
 
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
@@ -594,7 +594,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct atm_vcc *vcc;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        vcc = ATM_SD(sock);
index 8a96672e2c5c462fb3f575df3ba4d8c25a03727d..eb404dc3ed6e213e4148ba1f7b13bb1d0570a4e1 100644 (file)
@@ -424,7 +424,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 err2:
        br_fdb_delete_by_port(br, p, 1);
 err1:
-       kobject_del(&p->kobj);
+       kobject_put(&p->kobj);
 err0:
        dev_set_promiscuity(dev, -1);
 put_back:
index 95d7f32643aef3a3e0b3830200ea592bb1b54849..72720c7103515d6211da62c387f48f37ad69c56f 100644 (file)
@@ -75,6 +75,7 @@ static __initdata const char banner[] = KERN_INFO
 MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_ALIAS("can-proto-2");
 
 /* easy access to can_frame payload */
 static inline u64 GET_U64(const struct can_frame *cp)
@@ -1469,6 +1470,9 @@ static int bcm_release(struct socket *sock)
                bo->ifindex = 0;
        }
 
+       sock_orphan(sk);
+       sock->sk = NULL;
+
        release_sock(sk);
        sock_put(sk);
 
index 6aa154e806ae722c53e71603c0b22865526452a0..f4cc44548bdaa35a2b6947b8c7ef89affe8ac615 100644 (file)
@@ -62,6 +62,7 @@ static __initdata const char banner[] =
 MODULE_DESCRIPTION("PF_CAN raw protocol");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
+MODULE_ALIAS("can-proto-1");
 
 #define MASK_ALL 0
 
@@ -306,6 +307,9 @@ static int raw_release(struct socket *sock)
        ro->bound   = 0;
        ro->count   = 0;
 
+       sock_orphan(sk);
+       sock->sk = NULL;
+
        release_sock(sk);
        sock_put(sk);
 
index 58abee1f1df1b044514079f9245dc7c1b96978a3..b0fe69211eefef1e18224fa123d2b13498bffefa 100644 (file)
@@ -712,7 +712,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
index 9675f312830dd762bcd530eee90569de5a89b320..df30feb2fc725b047ef744273e7c506714bbac61 100644 (file)
@@ -740,7 +740,7 @@ int netpoll_setup(struct netpoll *np)
                                       np->name);
                                break;
                        }
-                       cond_resched();
+                       msleep(1);
                }
 
                /* If carrier appears to come up instantly, we don't
index b0ba569bc97361dec5b2619a46ffbeab50331dc2..bbb25be7ddfe614432ca8627ba4cbe791f57d569 100644 (file)
@@ -631,7 +631,7 @@ set_rcvbuf:
 
        case SO_TIMESTAMPING:
                if (val & ~SOF_TIMESTAMPING_MASK) {
-                       ret = EINVAL;
+                       ret = -EINVAL;
                        break;
                }
                sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE,
@@ -919,13 +919,19 @@ static inline void sock_lock_init(struct sock *sk)
                        af_family_keys + sk->sk_family);
 }
 
+/*
+ * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet,
+ * even temporarly, because of RCU lookups. sk_node should also be left as is.
+ */
 static void sock_copy(struct sock *nsk, const struct sock *osk)
 {
 #ifdef CONFIG_SECURITY_NETWORK
        void *sptr = nsk->sk_security;
 #endif
-
-       memcpy(nsk, osk, osk->sk_prot->obj_size);
+       BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
+                    sizeof(osk->sk_node) + sizeof(osk->sk_refcnt));
+       memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
+              osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
 #ifdef CONFIG_SECURITY_NETWORK
        nsk->sk_security = sptr;
        security_sk_clone(osk, nsk);
@@ -939,8 +945,23 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
        struct kmem_cache *slab;
 
        slab = prot->slab;
-       if (slab != NULL)
-               sk = kmem_cache_alloc(slab, priority);
+       if (slab != NULL) {
+               sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);
+               if (!sk)
+                       return sk;
+               if (priority & __GFP_ZERO) {
+                       /*
+                        * caches using SLAB_DESTROY_BY_RCU should let
+                        * sk_node.next un-modified. Special care is taken
+                        * when initializing object to zero.
+                        */
+                       if (offsetof(struct sock, sk_node.next) != 0)
+                               memset(sk, 0, offsetof(struct sock, sk_node.next));
+                       memset(&sk->sk_node.pprev, 0,
+                              prot->obj_size - offsetof(struct sock,
+                                                        sk_node.pprev));
+               }
+       }
        else
                sk = kmalloc(prot->obj_size, priority);
 
@@ -1125,6 +1146,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 
                newsk->sk_err      = 0;
                newsk->sk_priority = 0;
+               /*
+                * Before updating sk_refcnt, we must commit prior changes to memory
+                * (Documentation/RCU/rculist_nulls.txt for details)
+                */
+               smp_wmb();
                atomic_set(&newsk->sk_refcnt, 2);
 
                /*
@@ -1715,7 +1741,7 @@ EXPORT_SYMBOL(sock_no_sendpage);
 static void sock_def_wakeup(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_all(sk->sk_sleep);
        read_unlock(&sk->sk_callback_lock);
 }
@@ -1723,7 +1749,7 @@ static void sock_def_wakeup(struct sock *sk)
 static void sock_def_error_report(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_poll(sk->sk_sleep, POLLERR);
        sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
        read_unlock(&sk->sk_callback_lock);
@@ -1732,7 +1758,7 @@ static void sock_def_error_report(struct sock *sk)
 static void sock_def_readable(struct sock *sk, int len)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
                                                POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
@@ -1747,7 +1773,7 @@ static void sock_def_write_space(struct sock *sk)
         * progress.  --DaveM
         */
        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
 
@@ -1840,6 +1866,11 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        sk->sk_stamp = ktime_set(-1L, 0);
 
+       /*
+        * Before updating sk_refcnt, we must commit prior changes to memory
+        * (Documentation/RCU/rculist_nulls.txt for details)
+        */
+       smp_wmb();
        atomic_set(&sk->sk_refcnt, 1);
        atomic_set(&sk->sk_wmem_alloc, 1);
        atomic_set(&sk->sk_drops, 0);
index c0e88c16d0888b5222ca250c01a27bf3078a7e2a..c96119fda6885fd6b6bdc5487ff5cca7d2dd1574 100644 (file)
@@ -196,7 +196,7 @@ void dccp_write_space(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible(sk->sk_sleep);
        /* Should agree with poll, otherwise some programs break */
        if (sock_writeable(sk))
index 314a1b5c033c88950ddf73eccf30a34bcaf60191..94ca8eaace7d05988059838bd5477831d643b65f 100644 (file)
@@ -311,7 +311,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == DCCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
index 00a54b246dfed11ae46b4782e25a13ea3c8c3e61..63c2fa7b68c4b922840fe883bd9bdf0e9a6c21c7 100644 (file)
@@ -316,8 +316,8 @@ static inline void check_tnode(const struct tnode *tn)
 
 static const int halve_threshold = 25;
 static const int inflate_threshold = 50;
-static const int halve_threshold_root = 8;
-static const int inflate_threshold_root = 15;
+static const int halve_threshold_root = 15;
+static const int inflate_threshold_root = 25;
 
 
 static void __alias_free_mem(struct rcu_head *head)
index 44e2a3d2359afd99da1324022c221e811d83a0a9..cb4a0f4bd5e5654b465ddee4f32a42504711d5d3 100644 (file)
@@ -735,10 +735,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        tos = tiph->tos;
-       if (tos&1) {
+       if (tos == 1) {
+               tos = 0;
                if (skb->protocol == htons(ETH_P_IP))
                        tos = old_iph->tos;
-               tos &= ~1;
        }
 
        {
index 2470262826694d122b5457d6ef4144b66429d7a2..7d08210547291b74bc15d001e55eacdb8dd34281 100644 (file)
@@ -1243,7 +1243,6 @@ int ip_push_pending_frames(struct sock *sk)
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
index 7870a535dac6484ec7886dcf8e8270b729d3eaaa..91145244ea630777e7e4a2e7f112f3c31bc7f90e 100644 (file)
@@ -339,7 +339,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct sock *sk = sock->sk;
        struct tcp_sock *tp = tcp_sk(sk);
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        if (sk->sk_state == TCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
index 5a1ca2698c885775914f05fe17ae45d485cbddd2..6d88219c5e22bd4bf752a543bebfb5af4ae36a1f 100644 (file)
@@ -1160,6 +1160,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = {
 #ifdef CONFIG_TCP_MD5SIG
 static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
        .md5_lookup     =       tcp_v4_reqsk_md5_lookup,
+       .calc_md5_hash  =       tcp_v4_md5_hash_skb,
 };
 #endif
 
@@ -1373,7 +1374,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                 */
                char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
                if (newkey != NULL)
-                       tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr,
+                       tcp_v4_md5_do_add(newsk, newinet->daddr,
                                          newkey, key->keylen);
                newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
        }
index 5bdf08d312d9b9b13a824673da237001679c0bff..bd62712848fad8f1a116364002c23cfab903d49e 100644 (file)
@@ -2261,7 +2261,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 #ifdef CONFIG_TCP_MD5SIG
        /* Okay, we have all we need - do the md5 hash if needed */
        if (md5) {
-               tp->af_specific->calc_md5_hash(md5_hash_location,
+               tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location,
                                               md5, NULL, req, skb);
        }
 #endif
index 7c76e3d1821551c42acc16d3e2210404a553b4d0..87f8419a68fdf888b37a2643345d89b85005671d 100644 (file)
@@ -1484,7 +1484,6 @@ int ip6_push_pending_frames(struct sock *sk)
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
index 68e52308e5520f7180e22c0230aea51133fad265..98b7327d0949aa993751411f6512ebdf304f326f 100644 (file)
@@ -1018,6 +1018,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
        dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
+       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;
index 58810c65b6359524b171fa9ca0678b9a6a21241c..d849dd53b78810623e62555a85eff50af60d84d1 100644 (file)
@@ -896,6 +896,7 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
 #ifdef CONFIG_TCP_MD5SIG
 static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
        .md5_lookup     =       tcp_v6_reqsk_md5_lookup,
+       .calc_md5_hash  =       tcp_v6_md5_hash_skb,
 };
 #endif
 
@@ -1441,7 +1442,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                 */
                char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
                if (newkey != NULL)
-                       tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr,
+                       tcp_v6_md5_do_add(newsk, &newnp->daddr,
                                          newkey, key->keylen);
        }
 #endif
index 417b0e30949551de04cc6e1f8087ca9a7809da08..f1118d92a191dc07acd9bfda34ce81c7df8613f0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/netdevice.h>
 #include <linux/uio.h>
 #include <linux/skbuff.h>
+#include <linux/smp_lock.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/string.h>
index cb762c8723ea7a90f98b9e34074d98bc3b716742..80cf29aae0967a8935646ecda366b94168449a1a 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/smp_lock.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/init.h>
index bccf4d0059f0a6a629bbd5913015b0453caaa5e9..b001c361ad30976ff3a1de5bfe80fe2f0142b6f9 100644 (file)
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/skbuff.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
index 6d8ae03c14f5b8e3dc12af9906a14e1b0ae3b666..68cbcb19cbd8a084dc0121997c2701f970c99aa1 100644 (file)
@@ -13,6 +13,7 @@
  *     2) as a control channel (write commands, read events)
  */
 
+#include <linux/smp_lock.h>
 #include "irnet_ppp.h"         /* Private header */
 /* Please put other headers in irnet.h - Thanks */
 
index ecf4eb2717cb0c4d75b77aa006c8d15235c7d867..9cb79f95bf63953c9bcdf2b379b4ccbb37089ff5 100644 (file)
@@ -1453,6 +1453,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
        }
        /* Dup */
        memcpy(new, orig, sizeof(struct tsap_cb));
+       spin_lock_init(&new->lock);
 
        /* We don't need the old instance any more */
        spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
index 6be5f92d10943d383ce252242233e61770b2e528..49c15b48408e5617a5405ba396f1f9b9e427dd5d 100644 (file)
@@ -306,7 +306,7 @@ static inline int iucv_below_msglim(struct sock *sk)
 static void iucv_sock_wake_msglim(struct sock *sk)
 {
        read_lock(&sk->sk_callback_lock);
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+       if (sk_has_sleeper(sk))
                wake_up_interruptible_all(sk->sk_sleep);
        sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        read_unlock(&sk->sk_callback_lock);
@@ -1256,7 +1256,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
 
        if (sk->sk_state == IUCV_LISTEN)
                return iucv_accept_poll(sk);
index ba2643a43c73c662236ad8f79144dba39d5dcfad..7836ee92898369a7aa6e2c7f67539c48bf93ec11 100644 (file)
@@ -83,6 +83,7 @@ endmenu
 config MAC80211_MESH
        bool "Enable mac80211 mesh networking (pre-802.11s) support"
        depends on MAC80211 && EXPERIMENTAL
+       depends on BROKEN
        ---help---
         This options enables support of Draft 802.11s mesh networking.
         The implementation is based on Draft 1.08 of the Mesh Networking
index 003cb470ac8478c84329bf29a0687484a2e6acb1..f49ef288e2e28841a2e6308c2ab94e83cf2d1717 100644 (file)
@@ -637,7 +637,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_preq_queue *preq_node;
 
-       preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+       preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
        if (!preq_node) {
                printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
                return;
index 3c72557df45adee87cba306b2d560089e71cdb49..479597e885832d539f4774e157e48deff8d22da2 100644 (file)
@@ -175,6 +175,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
+       might_sleep();
+
        if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
@@ -265,6 +267,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
+       might_sleep();
 
        if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
@@ -491,8 +494,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
  * @skb: frame to discard
  * @sdata: network subif the frame was to be sent through
  *
- * If the frame was beign forwarded from another MP, a PERR frame will be sent
- * to the precursor.
+ * If the frame was being forwarded from another MP, a PERR frame will be sent
+ * to the precursor.  The precursor's address (i.e. the previous hop) was saved
+ * in addr1 of the frame-to-be-forwarded, and would only be overwritten once
+ * the destination is successfully resolved.
  *
  * Locking: the function must me called within a rcu_read_lock region
  */
@@ -507,7 +512,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
                u8 *ra, *da;
 
                da = hdr->addr3;
-               ra = hdr->addr2;
+               ra = hdr->addr1;
                mpath = mesh_path_lookup(da, sdata);
                if (mpath)
                        dsn = ++mpath->dsn;
index b218b98fba7fbeb573d420ca0829af99f47584c5..37771abd8f5a5bcd85d9d94fa558f0e69649defb 100644 (file)
@@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
        for (i = rix; i >= 0; i--)
                if (mi->r[i].rix == rix)
                        break;
-       WARN_ON(mi->r[i].rix != rix);
+       WARN_ON(i < 0);
        return i;
 }
 
@@ -181,6 +181,9 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
                        break;
 
                ndx = rix_to_ndx(mi, ar[i].idx);
+               if (ndx < 0)
+                       continue;
+
                mi->r[ndx].attempts += ar[i].count;
 
                if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
index d238a8939a094de63e1f9782a68b908a4340b998..3a8922cd1038ceaef3c4e4ddb433ac3e5c672e66 100644 (file)
@@ -1455,7 +1455,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                monitor_iface = UNKNOWN_ADDRESS;
 
                len_rthdr = ieee80211_get_radiotap_len(skb->data);
-               hdr = (struct ieee80211_hdr *)skb->data + len_rthdr;
+               hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
                hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
                /* check the header is complete in the frame */
index 7508f11c5b3952a05ed9b41682f50d7827b3c4e6..b5869b9574b08a52c4c16f04cdb3f17336f9d762 100644 (file)
@@ -561,23 +561,38 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
                }
        }
 
-       ct = kmem_cache_zalloc(nf_conntrack_cachep, gfp);
+       /*
+        * Do not use kmem_cache_zalloc(), as this cache uses
+        * SLAB_DESTROY_BY_RCU.
+        */
+       ct = kmem_cache_alloc(nf_conntrack_cachep, gfp);
        if (ct == NULL) {
                pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
                atomic_dec(&net->ct.count);
                return ERR_PTR(-ENOMEM);
        }
-
+       /*
+        * Let ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.next
+        * and ct->tuplehash[IP_CT_DIR_REPLY].hnnode.next unchanged.
+        */
+       memset(&ct->tuplehash[IP_CT_DIR_MAX], 0,
+              sizeof(*ct) - offsetof(struct nf_conn, tuplehash[IP_CT_DIR_MAX]));
        spin_lock_init(&ct->lock);
-       atomic_set(&ct->ct_general.use, 1);
        ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+       ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL;
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
+       ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
        /* Don't set timer yet: wait for confirmation */
        setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
 #ifdef CONFIG_NET_NS
        ct->ct_net = net;
 #endif
 
+       /*
+        * changes to lookup keys must be done before setting refcnt to 1
+        */
+       smp_wmb();
+       atomic_set(&ct->ct_general.use, 1);
        return ct;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
index 863e40977a4db6d0b37fcc670137032afec85839..0f482e2440b432434ac96bbf38a942340ef56350 100644 (file)
@@ -330,7 +330,8 @@ static bool xt_osf_match_packet(const struct sk_buff *skb,
                        fcount++;
 
                        if (info->flags & XT_OSF_LOG)
-                               nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL,
+                               nf_log_packet(p->family, p->hooknum, skb,
+                                       p->in, p->out, NULL,
                                        "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n",
                                        f->genre, f->version, f->subtype,
                                        &ip->saddr, ntohs(tcp->source),
@@ -345,7 +346,7 @@ static bool xt_osf_match_packet(const struct sk_buff *skb,
        rcu_read_unlock();
 
        if (!fcount && (info->flags & XT_OSF_LOG))
-               nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL,
+               nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL,
                        "Remote OS is not known: %pi4:%u -> %pi4:%u\n",
                                &ip->saddr, ntohs(tcp->source),
                                &ip->daddr, ntohs(tcp->dest));
index 79693fe2001e50df79d259a41dec1f6aa28b9370..2fc4a1724eb8e2e1fcacd6f0f55ea16c4afbd674 100644 (file)
@@ -549,6 +549,10 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
        swprev = !!(rfkill->state & RFKILL_BLOCK_SW);
        hwprev = !!(rfkill->state & RFKILL_BLOCK_HW);
        __rfkill_set_sw_state(rfkill, sw);
+       if (hw)
+               rfkill->state |= RFKILL_BLOCK_HW;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_HW;
 
        spin_unlock_irqrestore(&rfkill->lock, flags);
 
@@ -648,15 +652,26 @@ static ssize_t rfkill_state_store(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
-       /*
-        * The intention was that userspace can only take control over
-        * a given device when/if rfkill-input doesn't control it due
-        * to user_claim. Since user_claim is currently unsupported,
-        * we never support changing the state from userspace -- this
-        * can be implemented again later.
-        */
+       struct rfkill *rfkill = to_rfkill(dev);
+       unsigned long state;
+       int err;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       err = strict_strtoul(buf, 0, &state);
+       if (err)
+               return err;
+
+       if (state != RFKILL_USER_STATE_SOFT_BLOCKED &&
+           state != RFKILL_USER_STATE_UNBLOCKED)
+               return -EINVAL;
+
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_set_block(rfkill, state == RFKILL_USER_STATE_SOFT_BLOCKED);
+       mutex_unlock(&rfkill_global_mutex);
 
-       return -EPERM;
+       return err ?: count;
 }
 
 static ssize_t rfkill_claim_show(struct device *dev,
index 6bd8e93869eda9d6d5732bcf502ba32d7ca041db..f0a76f6bca711a064f4611a592c82eeca9968f0f 100644 (file)
@@ -92,23 +92,21 @@ static void rose_set_lockdep_key(struct net_device *dev)
 /*
  *     Convert a ROSE address into text.
  */
-const char *rose2asc(const rose_address *addr)
+char *rose2asc(char *buf, const rose_address *addr)
 {
-       static char buffer[11];
-
        if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 &&
            addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 &&
            addr->rose_addr[4] == 0x00) {
-               strcpy(buffer, "*");
+               strcpy(buf, "*");
        } else {
-               sprintf(buffer, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
+               sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
                                                addr->rose_addr[1] & 0xFF,
                                                addr->rose_addr[2] & 0xFF,
                                                addr->rose_addr[3] & 0xFF,
                                                addr->rose_addr[4] & 0xFF);
        }
 
-       return buffer;
+       return buf;
 }
 
 /*
@@ -1437,7 +1435,7 @@ static void rose_info_stop(struct seq_file *seq, void *v)
 
 static int rose_info_show(struct seq_file *seq, void *v)
 {
-       char buf[11];
+       char buf[11], rsbuf[11];
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq,
@@ -1455,8 +1453,8 @@ static int rose_info_show(struct seq_file *seq, void *v)
                        devname = dev->name;
 
                seq_printf(seq, "%-10s %-9s ",
-                       rose2asc(&rose->dest_addr),
-                       ax2asc(buf, &rose->dest_call));
+                          rose2asc(rsbuf, &rose->dest_addr),
+                          ax2asc(buf, &rose->dest_call));
 
                if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
                        callsign = "??????-?";
@@ -1465,7 +1463,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
 
                seq_printf(seq,
                           "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
-                       rose2asc(&rose->source_addr),
+                       rose2asc(rsbuf, &rose->source_addr),
                        callsign,
                        devname,
                        rose->lci & 0x0FFF,
index a81066a1010a869fa4885d7f3334df3195cfec25..9478d9b3d9777643bcd821fed4a380f8a4123553 100644 (file)
@@ -1104,6 +1104,7 @@ static void rose_node_stop(struct seq_file *seq, void *v)
 
 static int rose_node_show(struct seq_file *seq, void *v)
 {
+       char rsbuf[11];
        int i;
 
        if (v == SEQ_START_TOKEN)
@@ -1112,13 +1113,13 @@ static int rose_node_show(struct seq_file *seq, void *v)
                const struct rose_node *rose_node = v;
                /* if (rose_node->loopback) {
                        seq_printf(seq, "%-10s %04d 1 loopback\n",
-                               rose2asc(&rose_node->address),
-                               rose_node->mask);
+                                  rose2asc(rsbuf, &rose_node->address),
+                                  rose_node->mask);
                } else { */
                        seq_printf(seq, "%-10s %04d %d",
-                               rose2asc(&rose_node->address),
-                               rose_node->mask,
-                               rose_node->count);
+                                  rose2asc(rsbuf, &rose_node->address),
+                                  rose_node->mask,
+                                  rose_node->count);
 
                        for (i = 0; i < rose_node->count; i++)
                                seq_printf(seq, " %05d",
@@ -1267,7 +1268,7 @@ static void rose_route_stop(struct seq_file *seq, void *v)
 
 static int rose_route_show(struct seq_file *seq, void *v)
 {
-       char buf[11];
+       char buf[11], rsbuf[11];
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq,
@@ -1279,7 +1280,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
                        seq_printf(seq,
                                   "%3.3X  %-10s  %-9s  %05d      ",
                                   rose_route->lci1,
-                                  rose2asc(&rose_route->src_addr),
+                                  rose2asc(rsbuf, &rose_route->src_addr),
                                   ax2asc(buf, &rose_route->src_call),
                                   rose_route->neigh1->number);
                else
@@ -1289,10 +1290,10 @@ static int rose_route_show(struct seq_file *seq, void *v)
                if (rose_route->neigh2)
                        seq_printf(seq,
                                   "%3.3X  %-10s  %-9s  %05d\n",
-                               rose_route->lci2,
-                               rose2asc(&rose_route->dest_addr),
-                               ax2asc(buf, &rose_route->dest_call),
-                               rose_route->neigh2->number);
+                                  rose_route->lci2,
+                                  rose2asc(rsbuf, &rose_route->dest_addr),
+                                  ax2asc(buf, &rose_route->dest_call),
+                                  rose_route->neigh2->number);
                 else
                         seq_puts(seq,
                                  "000  *           *          00000\n");
index eac5e7bb73659c3b951bd7fc9f564e7d380e4d9b..bfe493ebf27c36a7a82974af5a596ee8f75528c9 100644 (file)
@@ -63,7 +63,7 @@ static void rxrpc_write_space(struct sock *sk)
        _enter("%p", sk);
        read_lock(&sk->sk_callback_lock);
        if (rxrpc_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible(sk->sk_sleep);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
@@ -588,7 +588,7 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* the socket is readable if there are any messages waiting on the Rx
index 5bc2f45bddf0051a90f73274707b2697cc53b5d0..ebfcf9b8990918d65db492add437ae46fa259e30 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kallsyms.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/utsname.h>
 #include <linux/workqueue.h>
 #include <linux/in6.h>
index 1102ce1251f7b61ad7d6a70a7df8826ce2a420c2..8f459abe97cff614525775560ec355f9d4c69246 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/mempool.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 
index 6f33d33cc064e0f39f3232c910aff09fd53b3a67..27d44332f0175968c0729646ae4641321104bbd6 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
index 36d4e44d62334275ffbfaa8e3b837e95bcdace5f..fc3ebb906911b955b33b39af1a6a2e729d4695c9 100644 (file)
@@ -315,7 +315,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))
+               if (sk_has_sleeper(sk))
                        wake_up_interruptible_sync(sk->sk_sleep);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
@@ -1985,7 +1985,7 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
@@ -2022,7 +2022,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk, *other;
        unsigned int mask, writable;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk->sk_sleep, wait);
        mask = 0;
 
        /* exceptional events? */
@@ -2053,7 +2053,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
                other = unix_peer_get(sk);
                if (other) {
                        if (unix_peer(other) != sk) {
-                               poll_wait(file, &unix_sk(other)->peer_wait,
+                               sock_poll_wait(file, &unix_sk(other)->peer_wait,
                                          wait);
                                if (unix_recvq_full(other))
                                        writable = 0;
index 466e2d22d256de7151551575607999ff6f1e95a9..258daa80ad926d80d86abcf06aaeb177514d1791 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>      /* support for loadable modules */
 #include <linux/slab.h>                /* kmalloc(), kfree() */
+#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/string.h>      /* inline mem*, str* functions */
 
index 241bddd0b4f19b2bb17009a295bf023345bfdc7c..634496b3ed77cb7adf5e1ec1356a307b6b897356 100644 (file)
@@ -447,6 +447,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
        rdev = __cfg80211_drv_from_info(info);
        if (IS_ERR(rdev)) {
+               mutex_unlock(&cfg80211_mutex);
                result = PTR_ERR(rdev);
                goto unlock;
        }
@@ -996,7 +997,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 
        if (IS_ERR(hdr)) {
                err = PTR_ERR(hdr);
-               goto out;
+               goto free_msg;
        }
 
        cookie.msg = msg;
@@ -1010,7 +1011,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
                                &cookie, get_key_callback);
 
        if (err)
-               goto out;
+               goto free_msg;
 
        if (cookie.error)
                goto nla_put_failure;
@@ -1021,6 +1022,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 
  nla_put_failure:
        err = -ENOBUFS;
+ free_msg:
        nlmsg_free(msg);
  out:
        cfg80211_put_dev(drv);
index e95b638b919f5dba4203a0959c0437fd612f239e..9271118e1fc48c492b69cdae50fab2981f4345d8 100644 (file)
@@ -35,8 +35,6 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
        else
                nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
 
-       wiphy_to_dev(request->wiphy)->scan_req = NULL;
-
 #ifdef CONFIG_WIRELESS_EXT
        if (!aborted) {
                memset(&wrqu, 0, sizeof(wrqu));
@@ -48,6 +46,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
        dev_put(dev);
 
  out:
+       wiphy_to_dev(request->wiphy)->scan_req = NULL;
        kfree(request);
 }
 EXPORT_SYMBOL(cfg80211_scan_done);
@@ -366,7 +365,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        found = rb_find_bss(dev, res);
 
        if (found) {
-               kref_get(&found->ref);
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
index 21cdc872004edbb4acba70070eadaa0ad8102e27..5e6c072c64d3d8b3380cc68247565fa291237952 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/net.h>
index 9977a756fb32102dae7b7e4eedf3130c20546e6f..f24ae370e514f77f04342c78d0d180e89e4001f4 100644 (file)
@@ -1,20 +1,3 @@
-/*
- * Notice that this file is not protected like a normal header.
- * We also must allow for rereading of this file. The
- *
- *  || defined(TRACE_HEADER_MULTI_READ)
- *
- * serves this purpose.
- */
-#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_EVENT_SAMPLE_H
-
-/*
- * All trace headers should include tracepoint.h, until we finally
- * make it into a standard header.
- */
-#include <linux/tracepoint.h>
-
 /*
  * If TRACE_SYSTEM is defined, that will be the directory created
  * in the ftrace directory under /debugfs/tracing/events/<system>
  * #define TRACE_INCLUDE_FILE trace-events-sample
  *
  * As we do an the bottom of this file.
+ *
+ * Notice that TRACE_SYSTEM should be defined outside of #if
+ * protection, just like TRACE_INCLUDE_FILE.
  */
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM sample
 
+/*
+ * Notice that this file is not protected like a normal header.
+ * We also must allow for rereading of this file. The
+ *
+ *  || defined(TRACE_HEADER_MULTI_READ)
+ *
+ * serves this purpose.
+ */
+#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_SAMPLE_H
+
+/*
+ * All trace headers should include tracepoint.h, until we finally
+ * make it into a standard header.
+ */
+#include <linux/tracepoint.h>
+
 /*
  * The TRACE_EVENT macro is broken up into 5 parts.
  *
index 86d95cca46a7cfc57922e50d8fd91b74fc8da745..f2375ad7ebc9bf07d306fc8de611f631b36cd7bf 100644 (file)
@@ -19,6 +19,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <stdarg.h>
+
 #include "dialog.h"
 
 struct dialog_info dlg;
index 3bcacb4bfd3af8284293a21fa202c886d3339126..25b60bc117f738fabc26efb9a2e8f4f7546cd8d1 100644 (file)
@@ -888,6 +888,8 @@ int main(int ac, char **av)
                        single_menu_mode = 1;
        }
 
+       initscr();
+
        getyx(stdscr, saved_y, saved_x);
        if (init_dialog(NULL)) {
                fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
index b19f1f4962e3dfdb852a4059bf3d1c6122963779..8b357b0bd250b0e04012a08815c01cd3f95f22a3 100644 (file)
@@ -89,7 +89,7 @@ for script in postinst postrm preinst prerm ; do
 set -e
 
 # Pass maintainer script parameters to hook scripts
-export DEB_MAINT_PARAMS="\$@"
+export DEB_MAINT_PARAMS="\$*"
 
 test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d
 exit 0
index 108b643229baecc3ec592eb300fbd4f332936c8c..6205f37d547ce80e0315be9d97fbc7ce7fa9ebe5 100644 (file)
@@ -75,7 +75,7 @@ int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-       if (rtd && rtd->params)
+       if (rtd && rtd->params && rtd->params->drcmr)
                *rtd->params->drcmr = 0;
 
        snd_pcm_set_runtime_buffer(substream, NULL);
index 333e4dd29450c7e9e823ebec46b7af4bcb6c62fc..72cfd47af6b8b4196ba6a77d52002e3a52ab9e18 100644 (file)
@@ -233,6 +233,18 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
                xrun(substream);
                return -EPIPE;
        }
+       if (xrun_debug(substream, 8)) {
+               char name[16];
+               pcm_debug_name(substream, name, sizeof(name));
+               snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, "
+                          "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
+                          name, (unsigned int)pos,
+                          (unsigned int)runtime->period_size,
+                          (unsigned int)runtime->buffer_size,
+                          (unsigned long)old_hw_ptr,
+                          (unsigned long)runtime->hw_ptr_base,
+                          (unsigned long)runtime->hw_ptr_interrupt);
+       }
        hw_base = runtime->hw_ptr_base;
        new_hw_ptr = hw_base + pos;
        hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
@@ -244,18 +256,27 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
                        delta = new_hw_ptr - hw_ptr_interrupt;
        }
        if (delta < 0) {
-               delta += runtime->buffer_size;
+               if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
+                       delta += runtime->buffer_size;
                if (delta < 0) {
                        hw_ptr_error(substream, 
                                     "Unexpected hw_pointer value "
                                     "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
                                     substream->stream, (long)pos,
                                     (long)hw_ptr_interrupt);
+#if 1
+                       /* simply skipping the hwptr update seems more
+                        * robust in some cases, e.g. on VMware with
+                        * inaccurate timer source
+                        */
+                       return 0; /* skip this update */
+#else
                        /* rebase to interrupt position */
                        hw_base = new_hw_ptr = hw_ptr_interrupt;
                        /* align hw_base to buffer_size */
                        hw_base -= hw_base % runtime->buffer_size;
                        delta = 0;
+#endif
                } else {
                        hw_base += runtime->buffer_size;
                        if (hw_base >= runtime->boundary)
@@ -344,6 +365,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
                xrun(substream);
                return -EPIPE;
        }
+       if (xrun_debug(substream, 16)) {
+               char name[16];
+               pcm_debug_name(substream, name, sizeof(name));
+               snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
+                          "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
+                          name, (unsigned int)pos,
+                          (unsigned int)runtime->period_size,
+                          (unsigned int)runtime->buffer_size,
+                          (unsigned long)old_hw_ptr,
+                          (unsigned long)runtime->hw_ptr_base,
+                          (unsigned long)runtime->hw_ptr_interrupt);
+       }
+
        hw_base = runtime->hw_ptr_base;
        new_hw_ptr = hw_base + pos;
 
index 1bcb360330e521f37b82bca91452b7cbc0db8803..941f64a853ebea266d24141af7c4dc71a053165a 100644 (file)
@@ -3,10 +3,6 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
 #
 
-ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-  obj-$(CONFIG_SND_SEQUENCER) += oss/
-endif
-
 snd-seq-device-objs := seq_device.o
 snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
                 seq_fifo.o seq_prioq.o seq_timer.o \
@@ -19,7 +15,8 @@ snd-seq-virmidi-objs := seq_virmidi.o
 
 obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
+  obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
+  obj-$(CONFIG_SND_SEQUENCER) += oss/
 endif
 obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
 
index edb11eefdfe3e2097f25037cd5bf507de817bdc7..2dcf45bf7293f1d68a3391226110ce34cc2b721d 100644 (file)
@@ -795,13 +795,13 @@ static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
                if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
                        continue;
                /* load real volume - better precision */
-               spin_lock_irqsave(&gus->reg_lock, flags);
+               spin_lock(&gus->reg_lock);
                snd_gf1_select_voice(gus, pvoice->number);
                snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
                vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
                snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
                pcmp->final_volume = 1;
-               spin_unlock_irqrestore(&gus->reg_lock, flags);
+               spin_unlock(&gus->reg_lock);
        }
        spin_unlock_irqrestore(&gus->voice_alloc, flags);
        return change;
index f24bf1ecb36d1fa060fda9d817d17a872b11e774..15e4138bce17ea4b42b2904bbe29b43095252d38 100644 (file)
@@ -325,9 +325,9 @@ static struct snd_pcm_hardware snd_ca0106_capture_hw = {
        .rate_max =             192000,
        .channels_min =         2,
        .channels_max =         2,
-       .buffer_bytes_max =     ((65536 - 64) * 8),
+       .buffer_bytes_max =     65536 - 128,
        .period_bytes_min =     64,
-       .period_bytes_max =     (65536 - 64),
+       .period_bytes_max =     32768 - 64,
        .periods_min =          2,
        .periods_max =          2,
        .fifo_size =            0,
index a1db51b3ead82f198483e5b948619ee01d082516..a7f4a671f7b7c51daa84db20e5bb7f4b2336f293 100644 (file)
@@ -242,13 +242,12 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
 
        /* Allocate mem for amixer resource */
        amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
-       if (NULL == amixer) {
-               err = -ENOMEM;
-               return err;
-       }
+       if (!amixer)
+               return -ENOMEM;
 
        /* Check whether there are sufficient
         * amixer resources to meet request. */
+       err = 0;
        spin_lock_irqsave(&mgr->mgr_lock, flags);
        for (i = 0; i < desc->msr; i++) {
                err = mgr_get_resource(&mgr->mgr, 1, &idx);
@@ -397,12 +396,11 @@ static int get_sum_rsc(struct sum_mgr *mgr,
 
        /* Allocate mem for sum resource */
        sum = kzalloc(sizeof(*sum), GFP_KERNEL);
-       if (NULL == sum) {
-               err = -ENOMEM;
-               return err;
-       }
+       if (!sum)
+               return -ENOMEM;
 
        /* Check whether there are sufficient sum resources to meet request. */
+       err = 0;
        spin_lock_irqsave(&mgr->mgr_lock, flags);
        for (i = 0; i < desc->msr; i++) {
                err = mgr_get_resource(&mgr->mgr, 1, &idx);
index 082e35c08c02956371fd69120d8fbe8ad7e1eeef..deb6cfa73600027646a3cfcd53041523fd76b875 100644 (file)
@@ -57,9 +57,9 @@ struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
 
 struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
        [LINEO1] = {.left = 0x40, .right = 0x41},
-       [LINEO2] = {.left = 0x70, .right = 0x71},
+       [LINEO2] = {.left = 0x60, .right = 0x61},
        [LINEO3] = {.left = 0x50, .right = 0x51},
-       [LINEO4] = {.left = 0x60, .right = 0x61},
+       [LINEO4] = {.left = 0x70, .right = 0x71},
        [LINEIM] = {.left = 0x45, .right = 0xc5},
        [SPDIFOO] = {.left = 0x00, .right = 0x01},
        [SPDIFIO] = {.left = 0x05, .right = 0x85},
index e1c145d8b702944472abe2a6bcd309a98a16bd90..df43a5cd3938beeb880d564ae3652639b5369770 100644 (file)
@@ -724,12 +724,11 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
 
        /* Allocate mem for SRCIMP resource */
        srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
-       if (NULL == srcimp) {
-               err = -ENOMEM;
-               return err;
-       }
+       if (!srcimp)
+               return -ENOMEM;
 
        /* Check whether there are sufficient SRCIMP resources. */
+       err = 0;
        spin_lock_irqsave(&mgr->mgr_lock, flags);
        for (i = 0; i < desc->msr; i++) {
                err = mgr_get_resource(&mgr->mgr, 1, &idx);
index 29272f2e95a07945cf805e6c75867f0f1e2cb762..b0275a05087015aa0c7d8680cd23c03f63830d40 100644 (file)
@@ -50,19 +50,22 @@ static void snd_hda_generate_beep(struct work_struct *work)
  * The tone frequency of beep generator on IDT/STAC codecs is
  * defined from the 8bit tone parameter, in Hz,
  *    freq = 48000 * (257 - tone) / 1024
- * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ * that is from 12kHz to 93.75Hz in steps of 46.875 Hz
  */
 static int beep_linear_tone(struct hda_beep *beep, int hz)
 {
+       if (hz <= 0)
+               return 0;
        hz *= 1000; /* fixed point */
-       hz = hz - DIGBEEP_HZ_MIN;
+       hz = hz - DIGBEEP_HZ_MIN
+               + DIGBEEP_HZ_STEP / 2; /* round to nearest step */
        if (hz < 0)
                hz = 0; /* turn off PC beep*/
        else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
-               hz = 0xff;
+               hz = 1; /* max frequency */
        else {
                hz /= DIGBEEP_HZ_STEP;
-               hz++;
+               hz = 255 - hz;
        }
        return hz;
 }
index 26d255de6bebb73b6fa51b39b740132b7c0b609c..88480c0c58a01fc0f08e6e15802e4493636bc176 100644 (file)
@@ -332,6 +332,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                                                  AC_VERB_GET_CONNECT_LIST, i);
                range_val = !!(parm & (1 << (shift-1))); /* ranges */
                val = parm & mask;
+               if (val == 0) {
+                       snd_printk(KERN_WARNING "hda_codec: "
+                                  "invalid CONNECT_LIST verb %x[%i]:%x\n",
+                                   nid, i, parm);
+                       return 0;
+               }
                parm >>= shift;
                if (range_val) {
                        /* ranges between the previous and this one */
index 1877d95d4aa6725807f4b77690dce7ab2f6c80d0..77c1b840ca8b081839bc9c5baad859d0cb8a8596 100644 (file)
@@ -1455,6 +1455,17 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                return err;
        }
        snd_pcm_limit_hw_rates(runtime);
+       /* sanity check */
+       if (snd_BUG_ON(!runtime->hw.channels_min) ||
+           snd_BUG_ON(!runtime->hw.channels_max) ||
+           snd_BUG_ON(!runtime->hw.formats) ||
+           snd_BUG_ON(!runtime->hw.rates)) {
+               azx_release_device(azx_dev);
+               hinfo->ops.close(hinfo, apcm->codec, substream);
+               snd_hda_power_down(apcm->codec);
+               mutex_unlock(&chip->open_mutex);
+               return -EINVAL;
+       }
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = substream;
        azx_dev->running = 0;
@@ -1463,13 +1474,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        runtime->private_data = azx_dev;
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
-
-       if (snd_BUG_ON(!runtime->hw.channels_min || !runtime->hw.channels_max))
-               return -EINVAL;
-       if (snd_BUG_ON(!runtime->hw.formats))
-               return -EINVAL;
-       if (snd_BUG_ON(!runtime->hw.rates))
-               return -EINVAL;
        return 0;
 }
 
@@ -2329,9 +2333,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        gcap = azx_readw(chip, GCAP);
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
-       /* ATI chips seems buggy about 64bit DMA addresses */
-       if (chip->driver_type == AZX_DRIVER_ATI)
-               gcap &= ~ICH6_GCAP_64OK;
+       /* disable SB600 64bit support for safety */
+       if ((chip->driver_type == AZX_DRIVER_ATI) ||
+           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+               struct pci_dev *p_smbus;
+               p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
+                                        PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+                                        NULL);
+               if (p_smbus) {
+                       if (p_smbus->revision < 0x30)
+                               gcap &= ~ICH6_GCAP_64OK;
+                       pci_dev_put(p_smbus);
+               }
+       }
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
index be7d25fa7f35a3e164cf858aa7f5c4b67afd9ac6..3da85caf8af1318c3a3124606e57545d66f1a8ae 100644 (file)
@@ -3754,7 +3754,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
        int mute = (!ucontrol->value.integer.value[0] &&
                    !ucontrol->value.integer.value[1]);
        /* toggle GPIO1 according to the mute state */
-       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+       snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
                            mute ? 0x02 : 0x0);
        return ret;
 }
index e661b21354beda752a926421ee64b729f412ec43..8c8b273116fbcc71bbe241bd6f9b63c69fbcd2ef 100644 (file)
@@ -4505,6 +4505,12 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
                                              &dig_nid, 1);
                if (err < 0)
                        continue;
+               if (dig_nid > 0x7f) {
+                       printk(KERN_ERR "alc880_auto: invalid dig_nid "
+                               "connection 0x%x for NID 0x%x\n", dig_nid,
+                               spec->autocfg.dig_out_pins[i]);
+                       continue;
+               }
                if (!i)
                        spec->multiout.dig_out_nid = dig_nid;
                else {
@@ -6919,9 +6925,6 @@ static struct hda_verb alc882_targa_verbs[] = {
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
        { } /* end */
 };
 
@@ -7241,7 +7244,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
+               .init_verbs = { alc882_init_verbs, alc880_gpio3_init_verbs,
+                               alc882_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -9238,7 +9242,8 @@ static struct alc_config_preset alc883_presets[] = {
        },
        [ALC883_TARGA_DIG] = {
                .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
@@ -9251,7 +9256,8 @@ static struct alc_config_preset alc883_presets[] = {
        },
        [ALC883_TARGA_2ch_DIG] = {
                .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
@@ -10625,6 +10631,18 @@ static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
        alc262_lenovo_3000_automute(codec, 1);
 }
 
+static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
+                                 int dir, int idx, long *valp)
+{
+       int i, change = 0;
+
+       for (i = 0; i < 2; i++, valp++)
+               change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
+                                                  HDA_AMP_MUTE,
+                                                  *valp ? 0 : HDA_AMP_MUTE);
+       return change;
+}
+
 /* bind hp and internal speaker mute (with plug check) */
 static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
@@ -10633,13 +10651,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-
+       change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
+       change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
        if (change)
                alc262_fujitsu_automute(codec, 0);
        return change;
@@ -10674,10 +10687,7 @@ static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-
+       change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
        if (change)
                alc262_lenovo_3000_automute(codec, 0);
        return change;
@@ -11848,12 +11858,7 @@ static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
-                                         HDA_AMP_MUTE,
-                                         valp[0] ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
-                                          HDA_AMP_MUTE,
-                                          valp[1] ? 0 : HDA_AMP_MUTE);
+       change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
        if (change)
                alc268_acer_automute(codec, 0);
        return change;
@@ -12878,9 +12883,9 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
 
 static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
index 14f3c3e0f62dec7618b97b7d5872148da9d02ef3..512f3b9b9a459e27450efad9cb8c875823a99496 100644 (file)
@@ -1590,8 +1590,6 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
-                     "SigmaTel",STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
@@ -2344,6 +2342,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+                     "SigmaTel", STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_9205_REF),
        /* Dell */
@@ -2378,6 +2378,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
                      "Dell Vostro 1500", STAC_9205_DELL_M42),
        /* Gateway */
+       SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
        SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
        {} /* terminator */
 };
@@ -4065,7 +4066,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
        jack->nid = nid;
        jack->type = type;
 
-       sprintf(name, "%s at %s %s Jack",
+       snprintf(name, sizeof(name), "%s at %s %s Jack",
                snd_hda_get_jack_type(def_conf),
                snd_hda_get_jack_connectivity(def_conf),
                snd_hda_get_jack_location(def_conf));
@@ -5854,6 +5855,8 @@ static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
 };
 
 static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+       SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
+                          "Sony VAIO F/S", STAC_9872_VAIO),
        {} /* terminator */
 };
 
@@ -5866,6 +5869,8 @@ static int patch_stac9872(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
        codec->spec = spec;
+       spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
+       spec->pin_nids = stac9872_pin_nids;
 
        spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
                                                        stac9872_models,
@@ -5877,8 +5882,6 @@ static int patch_stac9872(struct hda_codec *codec)
                stac92xx_set_config_regs(codec,
                                         stac9872_brd_tbl[spec->board_config]);
 
-       spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
-       spec->pin_nids = stac9872_pin_nids;
        spec->multiout.dac_nids = spec->dac_nids;
        spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
        spec->adc_nids = stac9872_adc_nids;
index 8e004fb6961add86847d11b2a128577488a7821b..9008b4b013aa7a6feddf45d52e55a8c994a5a45e 100644 (file)
@@ -210,7 +210,9 @@ struct via_spec {
        /* capture */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
+       hda_nid_t mux_nids[3];
        hda_nid_t dig_in_nid;
+       hda_nid_t dig_in_pin;
 
        /* capture source */
        const struct hda_input_mux *input_mux;
@@ -319,6 +321,9 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec,
                            pin_type);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
+       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, nid, 0, 
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
 }
 
 
@@ -387,27 +392,12 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       unsigned int vendor_id = codec->vendor_id;
-
-       /* AIW0  lydia 060801 add for correct sw0 input select */
-       if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x18, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-                 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x19, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
-                 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x17, &spec->cur_mux[adc_idx]);
-       else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x13, &spec->cur_mux[adc_idx]);
-       else
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            spec->adc_nids[adc_idx],
-                                            &spec->cur_mux[adc_idx]);
+
+       if (!spec->mux_nids[adc_idx])
+               return -EINVAL;
+       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                    spec->mux_nids[adc_idx],
+                                    &spec->cur_mux[adc_idx]);
 }
 
 static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
@@ -998,25 +988,11 @@ static int via_init(struct hda_codec *codec)
 
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
-               if (IS_VT1708_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+               if (spec->dig_in_pin) {
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_PIN_WIDGET_CONTROL,
                                            PIN_OUT);
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_EAPD_BTLENABLE, 0x02);
                }
        } else /* enable SPDIF-input pin */
@@ -1326,6 +1302,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+       spec->dig_in_pin = VT1708_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708_DIGIN_NID;
 
@@ -1352,6 +1329,34 @@ static int via_auto_init(struct hda_codec *codec)
        return 0;
 }
 
+static int get_mux_nids(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid, conn[8];
+       unsigned int type;
+       int i, n;
+
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               nid = spec->adc_nids[i];
+               while (nid) {
+                       type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
+                               >> AC_WCAP_TYPE_SHIFT;
+                       if (type == AC_WID_PIN)
+                               break;
+                       n = snd_hda_get_connections(codec, nid, conn,
+                                                   ARRAY_SIZE(conn));
+                       if (n <= 0)
+                               break;
+                       if (n > 1) {
+                               spec->mux_nids[i] = nid;
+                               break;
+                       }
+                       nid = conn[0];
+               }
+       }
+       return 0;
+}
+
 static int patch_vt1708(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1799,6 +1804,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+       spec->dig_in_pin = VT1709_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1709_DIGIN_NID;
 
@@ -1859,6 +1865,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -1952,6 +1959,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -2344,6 +2352,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
+       spec->dig_in_pin = VT1708B_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708B_DIGIN_NID;
 
@@ -2404,6 +2413,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2455,6 +2465,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2889,6 +2900,7 @@ static int patch_vt1708S(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708S_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
                spec->num_mixers++;
        }
@@ -3206,6 +3218,7 @@ static int patch_vt1702(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1702_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
                spec->num_mixers++;
        }
index 235a71e5ac8de6782f9d24027a347b5dc7852046..b5ca02e2038c9bb42c35c8a194c57974e15b6686 100644 (file)
@@ -2197,9 +2197,12 @@ static int __init alsa_card_riptide_init(void)
        if (err < 0)
                return err;
 #if defined(SUPPORT_JOYSTICK)
-       pci_register_driver(&joystick_driver);
+       err = pci_register_driver(&joystick_driver);
+       /* On failure unregister formerly registered audio driver */
+       if (err < 0)
+               pci_unregister_driver(&driver);
 #endif
-       return 0;
+       return err;
 }
 
 static void __exit alsa_card_riptide_exit(void)
index ab099f482487b7e642d0f3d1372e6001673b3d27..cb0d1bf34b5723b9933ffc023430100b0594511d 100644 (file)
@@ -767,6 +767,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
        u16 pll_d = 1;
+       u8 reg;
 
        /* select data word length */
        data =
@@ -801,8 +802,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                pll_q &= 0xf;
                aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
                aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
-       } else
+               /* disable PLL if it is bypassed */
+               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+
+       } else {
                aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+               /* enable PLL when it is used */
+               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+       }
 
        /* Route Left DAC to left channel input and
         * right DAC to right channel input */
index d28eeaceb8573a504f3c7c5471f9f2f296c5618c..49c4b2898aff50beaa33e82f1dfcb9c5ea615106 100644 (file)
@@ -79,7 +79,7 @@ static const u16 wm8753_reg[] = {
        0x0097, 0x0097, 0x0000, 0x0004,
        0x0000, 0x0083, 0x0024, 0x01ba,
        0x0000, 0x0083, 0x0024, 0x01ba,
-       0x0000, 0x0000
+       0x0000, 0x0000, 0x0000
 };
 
 /* codec private data */
@@ -1660,11 +1660,11 @@ static int wm8753_register(struct wm8753_priv *wm8753)
        codec->set_bias_level = wm8753_set_bias_level;
        codec->dai = wm8753_dai;
        codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache);
+       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
        codec->reg_cache = &wm8753->reg_cache;
        codec->private_data = wm8753;
 
-       memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache));
+       memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
        INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
 
        ret = wm8753_reset(codec);
index c05f71803aa8a30f07da731d70591800c5a844fe..8c0fdf84aac341bf3718d73f6255f714cd66cb47 100644 (file)
@@ -1037,14 +1037,14 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi)
        codec->control_data = spi;
        codec->dev = &spi->dev;
 
-       spi->dev.driver_data = wm8988;
+       dev_set_drvdata(&spi->dev, wm8988);
 
        return wm8988_register(wm8988);
 }
 
 static int __devexit wm8988_spi_remove(struct spi_device *spi)
 {
-       struct wm8988_priv *wm8988 = spi->dev.driver_data;
+       struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
 
        wm8988_unregister(wm8988);
 
index efec33a1c5bddc443e56b0807f76aace8c58a569..f0a2d407199815fcbfc0cc0b2b3483d91e7d85e8 100644 (file)
@@ -456,6 +456,7 @@ int mpc5200_audio_dma_create(struct of_device *op)
                return -ENODEV;
 
        spin_lock_init(&psc_dma->lock);
+       mutex_init(&psc_dma->mutex);
        psc_dma->id = be32_to_cpu(*prop);
        psc_dma->irq = irq;
        psc_dma->psc_regs = regs;
index 2000803f06a721f236d7caae1104993cedbfeff7..8d396bb9d9fe405db9c10dc12d14e2dedabfaf58 100644 (file)
@@ -55,6 +55,7 @@ struct psc_dma {
        unsigned int irq;
        struct device *dev;
        spinlock_t lock;
+       struct mutex mutex;
        u32 sicr;
        uint sysclk;
        int imr;
index 794a247b3eb55ec758a55a9b21e43533cc25e891..7eb549985d490cef5bc1cd3a6717020bea2b5fb4 100644 (file)
@@ -34,13 +34,20 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
        int status;
        unsigned int val;
 
+       mutex_lock(&psc_dma->mutex);
+
        /* Wait for command send status zero = ready */
        status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
                                MPC52xx_PSC_SR_CMDSEND), 100, 0);
        if (status == 0) {
                pr_err("timeout on ac97 bus (rdy)\n");
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
+
+       /* Force clear the data valid bit */
+       in_be32(&psc_dma->psc_regs->ac97_data);
+
        /* Send the read */
        out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
 
@@ -50,16 +57,19 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
        if (status == 0) {
                pr_err("timeout on ac97 read (val) %x\n",
                                in_be16(&psc_dma->psc_regs->sr_csr.status));
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
        /* Get the data */
        val = in_be32(&psc_dma->psc_regs->ac97_data);
        if (((val >> 24) & 0x7f) != reg) {
                pr_err("reg echo error on ac97 read\n");
+               mutex_unlock(&psc_dma->mutex);
                return -ENODEV;
        }
        val = (val >> 8) & 0xffff;
 
+       mutex_unlock(&psc_dma->mutex);
        return (unsigned short) val;
 }
 
@@ -68,16 +78,21 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
 {
        int status;
 
+       mutex_lock(&psc_dma->mutex);
+
        /* Wait for command status zero = ready */
        status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
                                MPC52xx_PSC_SR_CMDSEND), 100, 0);
        if (status == 0) {
                pr_err("timeout on ac97 bus (write)\n");
-               return;
+               goto out;
        }
        /* Write data */
        out_be32(&psc_dma->psc_regs->ac97_cmd,
                        ((reg & 0x7f) << 24) | (val << 8));
+
+ out:
+       mutex_unlock(&psc_dma->mutex);
 }
 
 static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
index 523aec188ccf64efa2de3aae90f8550eee77e3aa..73525c048e7f60d7613eef093f850c6d204215e4 100644 (file)
@@ -48,6 +48,7 @@ config SND_USB_CAIAQ
            * Native Instruments Kore Controller
            * Native Instruments Kore Controller 2
            * Native Instruments Audio Kontrol 1
+           * Native Instruments Audio 2 DJ
            * Native Instruments Audio 4 DJ
            * Native Instruments Audio 8 DJ
            * Native Instruments Guitar Rig Session I/O
index 8f9b60c5d74c9714e13c58a8bf4590b9e727951d..121af0644fd9bc901fbbc62cb676738e9049e0c7 100644 (file)
@@ -646,6 +646,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
                dev->samplerates |= SNDRV_PCM_RATE_192000;
                /* fall thru */
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
                dev->samplerates |= SNDRV_PCM_RATE_88200;
index de38108f0b283ab4653693cbe9ac77698de299a1..83e6c1312d47c47ef1cc32eabab5b411d9dfa6b3 100644 (file)
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.18");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.19");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
                         "{Native Instruments, Kore Controller},"
                         "{Native Instruments, Kore Controller 2},"
                         "{Native Instruments, Audio Kontrol 1},"
+                        "{Native Instruments, Audio 2 DJ},"
                         "{Native Instruments, Audio 4 DJ},"
                         "{Native Instruments, Audio 8 DJ},"
                         "{Native Instruments, Session I/O},"
@@ -121,6 +122,11 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_AUDIO4DJ
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_AUDIO2DJ
+       },
        { /* terminator */ }
 };
 
index ece73514854e2f302ab88da1d1a857d3f43ee3ec..44e3edf88befab4ce60071a3d9b9da72bd9a727e 100644 (file)
@@ -10,6 +10,7 @@
 #define USB_PID_KORECONTROLLER 0x4711
 #define USB_PID_KORECONTROLLER2        0x4712
 #define USB_PID_AK1            0x0815
+#define USB_PID_AUDIO2DJ       0x041c
 #define USB_PID_AUDIO4DJ       0x0839
 #define USB_PID_AUDIO8DJ       0x1978
 #define USB_PID_SESSIONIO      0x1915
index c7b902358b7b268a3dd25178639f41009dedf125..44b9cdc8a83bae15856ca18fb7915acc7197757d 100644 (file)
@@ -2661,7 +2661,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        struct usb_interface_descriptor *altsd;
        int i, altno, err, stream;
        int format;
-       struct audioformat *fp;
+       struct audioformat *fp = NULL;
        unsigned char *fmt, *csep;
        int num;
 
@@ -2734,6 +2734,18 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
                }
 
+               /*
+                * Blue Microphones workaround: The last altsetting is identical
+                * with the previous one, except for a larger packet size, but
+                * is actually a mislabeled two-channel setting; ignore it.
+                */
+               if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+                   fp && fp->altsetting == 1 && fp->channels == 1 &&
+                   fp->format == SNDRV_PCM_FORMAT_S16_LE &&
+                   le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
+                                                       fp->maxpacksize * 2)
+                       continue;
+
                csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
                /* Creamware Noah has this descriptor after the 2nd endpoint */
                if (!csep && altsd->bNumEndpoints >= 2)
index 4bd3a7a0edc100c2dd6007a98f8247b9084b8969..ec9cdf986928cfd1ce1847b18e111fdb71552fba 100644 (file)
@@ -990,20 +990,35 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
                break;
        }
 
-       /* quirk for UDA1321/N101 */
-       /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
-       /* is not very clear from datasheets */
-       /* I hope that the min value is -15360 for newer firmware --jk */
+       /* volume control quirks */
        switch (state->chip->usb_id) {
        case USB_ID(0x0471, 0x0101):
        case USB_ID(0x0471, 0x0104):
        case USB_ID(0x0471, 0x0105):
        case USB_ID(0x0672, 0x1041):
+       /* quirk for UDA1321/N101.
+        * note that detection between firmware 2.1.1.7 (N101)
+        * and later 2.1.1.21 is not very clear from datasheets.
+        * I hope that the min value is -15360 for newer firmware --jk
+        */
                if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
                    cval->min == -15616) {
-                       snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n");
+                       snd_printk(KERN_INFO
+                                "set volume quirk for UDA1321/N101 chip\n");
                        cval->max = -256;
                }
+               break;
+
+       case USB_ID(0x046d, 0x09a4):
+               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+                       snd_printk(KERN_INFO
+                               "set volume quirk for QuickCam E3500\n");
+                       cval->min = 6080;
+                       cval->max = 8768;
+                       cval->res = 192;
+               }
+               break;
+
        }
 
        snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
index 8aa3f8c88707f1ab9ea48f123833139ca8cc3ed7..e72e931107826e069d5bfabc3677dca7a2745af6 100644 (file)
@@ -24,6 +24,9 @@ OPTIONS
 --dsos=::
        Only consider symbols in these dsos. CSV that understands
        file://filename entries.
+-n
+--show-nr-samples
+       Show the number of samples for each symbol
 -C::
 --comms=::
        Only consider symbols in these comms. CSV that understands
@@ -33,6 +36,18 @@ OPTIONS
        Only consider these symbols. CSV that understands
        file://filename entries.
 
+-w::
+--field-width=::
+       Force each column width to the provided list, for large terminal
+       readability.
+
+-t::
+--field-separator=::
+
+       Use a special separator character and don't pad with spaces, replacing
+       all occurances of this separator in symbol names (and other output)
+       with a '.' character, that thus it's the only non valid separator.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1]
index 9c6d0ae3708e04b6fa2a6bcf40dfede08a5eaa2e..a5e9b876ca099668b4bad99c35871798e19009e7 100644 (file)
@@ -164,7 +164,7 @@ endif
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
-CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
+CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
 LDFLAGS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
@@ -223,7 +223,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 # Those must not be GNU-specific; they are shared with perl/ which may
 # be built by a different compiler. (Note that this is an artifact now
 # but it still might be nice to keep that distinction.)
-BASIC_CFLAGS =
+BASIC_CFLAGS = -Iutil/include
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -289,10 +289,11 @@ export PERL_PATH
 LIB_FILE=libperf.a
 
 LIB_H += ../../include/linux/perf_counter.h
+LIB_H += ../../include/linux/rbtree.h
+LIB_H += ../../include/linux/list.h
+LIB_H += util/include/linux/list.h
 LIB_H += perf.h
 LIB_H += util/types.h
-LIB_H += util/list.h
-LIB_H += util/rbtree.h
 LIB_H += util/levenshtein.h
 LIB_H += util/parse-options.h
 LIB_H += util/parse-events.h
@@ -305,6 +306,7 @@ LIB_H += util/strlist.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
+LIB_H += util/module.h
 LIB_H += util/color.h
 
 LIB_OBJS += util/abspath.o
@@ -328,6 +330,7 @@ LIB_OBJS += util/usage.o
 LIB_OBJS += util/wrapper.o
 LIB_OBJS += util/sigchain.o
 LIB_OBJS += util/symbol.o
+LIB_OBJS += util/module.o
 LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
 LIB_OBJS += util/header.o
@@ -342,7 +345,7 @@ BUILTIN_OBJS += builtin-stat.o
 BUILTIN_OBJS += builtin-top.o
 
 PERFLIBS = $(LIB_FILE)
-EXTLIBS =
+EXTLIBS = -lbfd
 
 #
 # Platform specific tweaks
@@ -381,12 +384,6 @@ ifndef CC_LD_DYNPATH
        endif
 endif
 
-ifdef ZLIB_PATH
-       BASIC_CFLAGS += -I$(ZLIB_PATH)/include
-       EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
-endif
-EXTLIBS += -lz
-
 ifdef NEEDS_SOCKET
        EXTLIBS += -lsocket
 endif
@@ -697,6 +694,9 @@ builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
 util/config.o: util/config.c PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
 perf-%$X: %.o $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
index 722c0f54e549e9742380e71a71b4ccfa353ade25..1dba568e19410d254b9bdfb1401d04316abbe48d 100644 (file)
@@ -10,9 +10,9 @@
 #include "util/util.h"
 
 #include "util/color.h"
-#include "util/list.h"
+#include <linux/list.h>
 #include "util/cache.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/string.h"
 
 #define SHOW_USER      2
 #define SHOW_HV                4
 
-#define MIN_GREEN              0.5
-#define MIN_RED                5.0
-
-
 static char            const *input_name = "perf.data";
 static char            *vmlinux = "vmlinux";
 
@@ -43,6 +39,10 @@ static int           dump_trace = 0;
 
 static int             verbose;
 
+static int             modules;
+
+static int             full_paths;
+
 static int             print_line;
 
 static unsigned long   page_size;
@@ -74,20 +74,12 @@ struct fork_event {
        u32 pid, ppid;
 };
 
-struct period_event {
-       struct perf_event_header header;
-       u64 time;
-       u64 id;
-       u64 sample_period;
-};
-
 typedef union event_union {
        struct perf_event_header        header;
        struct ip_event                 ip;
        struct mmap_event               mmap;
        struct comm_event               comm;
        struct fork_event               fork;
-       struct period_event             period;
 } event_t;
 
 
@@ -160,7 +152,7 @@ static void dsos__fprintf(FILE *fp)
 
 static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
 {
-       return dso__find_symbol(kernel_dso, ip);
+       return dso__find_symbol(dso, ip);
 }
 
 static int load_kernel(void)
@@ -171,8 +163,8 @@ static int load_kernel(void)
        if (!kernel_dso)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
-       if (err) {
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
                dso__delete(kernel_dso);
                kernel_dso = NULL;
        } else
@@ -203,7 +195,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static u64 vdso__map_ip(struct map *map, u64 ip)
+static u64 vdso__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
@@ -600,7 +592,7 @@ static LIST_HEAD(hist_entry__sort_list);
 
 static int sort_dimension__add(char *tok)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
                struct sort_dimension *sd = &sort_dimensions[i];
@@ -997,19 +989,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static int
-process_period_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->period.time,
-               event->period.id,
-               event->period.sample_period);
-
-       return 0;
-}
-
 static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
@@ -1025,9 +1004,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
 
        case PERF_EVENT_FORK:
                return process_fork_event(event, offset, head);
-
-       case PERF_EVENT_PERIOD:
-               return process_period_event(event, offset, head);
        /*
         * We dont process them right now but they are fine:
         */
@@ -1043,24 +1019,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static char *get_color(double percent)
-{
-       char *color = PERF_COLOR_NORMAL;
-
-       /*
-        * We color high-overhead entries in red, mid-overhead
-        * entries in green - and keep the low overhead places
-        * normal:
-        */
-       if (percent >= MIN_RED)
-               color = PERF_COLOR_RED;
-       else {
-               if (percent > MIN_GREEN)
-                       color = PERF_COLOR_GREEN;
-       }
-       return color;
-}
-
 static int
 parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
 {
@@ -1069,7 +1027,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
        static const char *prev_color;
        unsigned int offset;
        size_t line_len;
-       u64 line_ip;
+       s64 line_ip;
        int ret;
        char *c;
 
@@ -1122,7 +1080,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
                } else if (sym->hist_sum)
                        percent = 100.0 * hits / sym->hist_sum;
 
-               color = get_color(percent);
+               color = get_percent_color(percent);
 
                /*
                 * Also color the filename and line if needed, with
@@ -1258,7 +1216,7 @@ static void print_summary(char *filename)
 
                sym_ext = rb_entry(node, struct sym_ext, node);
                percent = sym_ext->percent;
-               color = get_color(percent);
+               color = get_percent_color(percent);
                path = sym_ext->path;
 
                color_fprintf(stdout, color, " %7.2f %s", percent, path);
@@ -1268,19 +1226,25 @@ static void print_summary(char *filename)
 
 static void annotate_sym(struct dso *dso, struct symbol *sym)
 {
-       char *filename = dso->name;
+       char *filename = dso->name, *d_filename;
        u64 start, end, len;
        char command[PATH_MAX*2];
        FILE *file;
 
        if (!filename)
                return;
-       if (dso == kernel_dso)
+       if (sym->module)
+               filename = sym->module->path;
+       else if (dso == kernel_dso)
                filename = vmlinux;
 
        start = sym->obj_start;
        if (!start)
                start = sym->start;
+       if (full_paths)
+               d_filename = filename;
+       else
+               d_filename = basename(filename);
 
        end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
@@ -1291,13 +1255,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
        }
 
        printf("\n\n------------------------------------------------\n");
-       printf(" Percent |      Source code & Disassembly of %s\n", filename);
+       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
        printf("------------------------------------------------\n");
 
        if (verbose >= 2)
                printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
 
-       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
+       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
+                       (u64)start, (u64)end, filename, filename);
 
        if (verbose >= 3)
                printf("doing: %s\n", command);
@@ -1428,7 +1393,7 @@ more:
 
        head += size;
 
-       if (offset + head < stat.st_size)
+       if (offset + head < (unsigned long)stat.st_size)
                goto more;
 
        rc = EXIT_SUCCESS;
@@ -1472,8 +1437,12 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &modules,
+                   "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('l', "print-line", &print_line,
                    "print matching source lines (may be slow)"),
+       OPT_BOOLEAN('P', "full-paths", &full_paths,
+                   "Don't shorten the displayed pathnames"),
        OPT_END()
 };
 
@@ -1492,7 +1461,7 @@ static void setup_sorting(void)
        free(str);
 }
 
-int cmd_annotate(int argc, const char **argv, const char *prefix)
+int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
        symbol__init();
 
index 0f32dc3f3c4c7a45b5d18bf8fac59aabedb8069f..2599d86a733b404db9be615519fec61b3517a1dd 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Builtin help command
  */
+#include "perf.h"
 #include "util/cache.h"
 #include "builtin.h"
 #include "util/exec_cmd.h"
@@ -277,7 +278,7 @@ static struct cmdnames main_cmds, other_cmds;
 
 void list_common_cmds_help(void)
 {
-       int i, longest = 0;
+       unsigned int i, longest = 0;
 
        for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
                if (longest < strlen(common_cmds[i].name))
@@ -415,9 +416,10 @@ static void show_html_page(const char *perf_cmd)
        open_html(page_path.buf);
 }
 
-int cmd_help(int argc, const char **argv, const char *prefix)
+int cmd_help(int argc, const char **argv, const char *prefix __used)
 {
        const char *alias;
+
        load_command_list("perf-", &main_cmds, &other_cmds);
 
        perf_config(perf_help_config, NULL);
index fe60e37c96efc85e60e83d59d1cdb7127fe198c8..f990fa8a35c9d3312a20f3dcc1498203574c9407 100644 (file)
@@ -13,7 +13,7 @@
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
-int cmd_list(int argc, const char **argv, const char *prefix)
+int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
 {
        print_events();
        return 0;
index d18546f37d7c5661cfa0d6d55c7d921124461d00..6da09928130f8b726446e21e55b4a114a02926dd 100644 (file)
@@ -43,6 +43,7 @@ static int                    call_graph                      = 0;
 static int                     verbose                         = 0;
 static int                     inherit_stat                    = 0;
 static int                     no_samples                      = 0;
+static int                     sample_address                  = 0;
 
 static long                    samples;
 static struct timeval          last_read;
@@ -294,7 +295,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
        while (1) {
                char bf[BUFSIZ], *pbf = bf;
                struct mmap_event mmap_ev = {
-                       .header.type = PERF_EVENT_MMAP,
+                       .header = { .type = PERF_EVENT_MMAP },
                };
                int n;
                size_t size;
@@ -313,6 +314,10 @@ static void pid_synthesize_mmap_samples(pid_t pid)
                if (*pbf == 'x') { /* vm_exec */
                        char *execname = strchr(bf, '/');
 
+                       /* Catch VDSO */
+                       if (execname == NULL)
+                               execname = strstr(bf, "[vdso]");
+
                        if (execname == NULL)
                                continue;
 
@@ -401,6 +406,9 @@ static void create_counter(int counter, int cpu, pid_t pid)
        if (inherit_stat)
                attr->inherit_stat = 1;
 
+       if (sample_address)
+               attr->sample_type       |= PERF_SAMPLE_ADDR;
+
        if (call_graph)
                attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
 
@@ -645,16 +653,19 @@ static const struct option options[] = {
                    "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('s', "stat", &inherit_stat,
                    "per thread counts"),
+       OPT_BOOLEAN('d', "data", &sample_address,
+                   "Sample addresses"),
        OPT_BOOLEAN('n', "no-samples", &no_samples,
                    "don't sample"),
        OPT_END()
 };
 
-int cmd_record(int argc, const char **argv, const char *prefix)
+int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
-       argc = parse_options(argc, argv, options, record_usage, 0);
+       argc = parse_options(argc, argv, options, record_usage,
+               PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && !system_wide)
                usage_with_options(record_usage, options);
 
index 135b7837e6bf3de20575d8c28bf0ee63037aab9e..b20a4b6e31b72938b1312bb64f333236bbf4cd88 100644 (file)
@@ -10,9 +10,9 @@
 #include "util/util.h"
 
 #include "util/color.h"
-#include "util/list.h"
+#include <linux/list.h>
 #include "util/cache.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/string.h"
 #include "util/callchain.h"
@@ -33,8 +33,10 @@ static char          *vmlinux = NULL;
 
 static char            default_sort_order[] = "comm,dso";
 static char            *sort_order = default_sort_order;
-static char            *dso_list_str, *comm_list_str, *sym_list_str;
+static char            *dso_list_str, *comm_list_str, *sym_list_str,
+                       *col_width_list_str;
 static struct strlist  *dso_list, *comm_list, *sym_list;
+static char            *field_sep;
 
 static int             input;
 static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
@@ -46,7 +48,10 @@ static int           dump_trace = 0;
 static int             verbose;
 #define eprintf(x...)  do { if (verbose) fprintf(stderr, x); } while (0)
 
+static int             modules;
+
 static int             full_paths;
+static int             show_nr_samples;
 
 static unsigned long   page_size;
 static unsigned long   mmap_window = 32;
@@ -56,8 +61,17 @@ static char          *parent_pattern = default_parent_pattern;
 static regex_t         parent_regex;
 
 static int             exclude_other = 1;
+
+static char            callchain_default_opt[] = "fractal,0.5";
+
 static int             callchain;
 
+static
+struct callchain_param callchain_param = {
+       .mode   = CHAIN_GRAPH_ABS,
+       .min_percent = 0.5
+};
+
 static u64             sample_type;
 
 struct ip_event {
@@ -87,13 +101,6 @@ struct fork_event {
        u32 pid, ppid;
 };
 
-struct period_event {
-       struct perf_event_header header;
-       u64 time;
-       u64 id;
-       u64 sample_period;
-};
-
 struct lost_event {
        struct perf_event_header header;
        u64 id;
@@ -113,14 +120,41 @@ typedef union event_union {
        struct mmap_event               mmap;
        struct comm_event               comm;
        struct fork_event               fork;
-       struct period_event             period;
        struct lost_event               lost;
        struct read_event               read;
 } event_t;
 
+static int repsep_fprintf(FILE *fp, const char *fmt, ...)
+{
+       int n;
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (!field_sep)
+               n = vfprintf(fp, fmt, ap);
+       else {
+               char *bf = NULL;
+               n = vasprintf(&bf, fmt, ap);
+               if (n > 0) {
+                       char *sep = bf;
+                       while (1) {
+                               sep = strchr(sep, *field_sep);
+                               if (sep == NULL)
+                                       break;
+                               *sep = '.';
+                       }
+               }
+               fputs(bf, fp);
+               free(bf);
+       }
+       va_end(ap);
+       return n;
+}
+
 static LIST_HEAD(dsos);
 static struct dso *kernel_dso;
 static struct dso *vdso;
+static struct dso *hypervisor_dso;
 
 static void dsos__add(struct dso *dso)
 {
@@ -176,7 +210,7 @@ static void dsos__fprintf(FILE *fp)
 
 static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
 {
-       return dso__find_symbol(kernel_dso, ip);
+       return dso__find_symbol(dso, ip);
 }
 
 static int load_kernel(void)
@@ -187,8 +221,8 @@ static int load_kernel(void)
        if (!kernel_dso)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
-       if (err) {
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
                dso__delete(kernel_dso);
                kernel_dso = NULL;
        } else
@@ -202,6 +236,11 @@ static int load_kernel(void)
 
        dsos__add(vdso);
 
+       hypervisor_dso = dso__new("[hypervisor]", 0);
+       if (!hypervisor_dso)
+               return -1;
+       dsos__add(hypervisor_dso);
+
        return err;
 }
 
@@ -233,7 +272,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static u64 vdso__map_ip(struct map *map, u64 ip)
+static u64 vdso__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
@@ -343,12 +382,28 @@ static struct thread *thread__new(pid_t pid)
        return self;
 }
 
+static unsigned int dsos__col_width,
+                   comms__col_width,
+                   threads__col_width;
+
 static int thread__set_comm(struct thread *self, const char *comm)
 {
        if (self->comm)
                free(self->comm);
        self->comm = strdup(comm);
-       return self->comm ? 0 : -ENOMEM;
+       if (!self->comm)
+               return -ENOMEM;
+
+       if (!col_width_list_str && !field_sep &&
+           (!comm_list || strlist__has_entry(comm_list, comm))) {
+               unsigned int slen = strlen(comm);
+               if (slen > comms__col_width) {
+                       comms__col_width = slen;
+                       threads__col_width = slen + 6;
+               }
+       }
+
+       return 0;
 }
 
 static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -519,7 +574,9 @@ struct sort_entry {
 
        int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
        int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
-       size_t  (*print)(FILE *fp, struct hist_entry *);
+       size_t  (*print)(FILE *fp, struct hist_entry *, unsigned int width);
+       unsigned int *width;
+       bool    elide;
 };
 
 static int64_t cmp_null(void *l, void *r)
@@ -541,15 +598,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self)
+sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
 {
-       return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
+       return repsep_fprintf(fp, "%*s:%5d", width - 6,
+                             self->thread->comm ?: "", self->thread->pid);
 }
 
 static struct sort_entry sort_thread = {
-       .header = "         Command:  Pid",
+       .header = "Command:  Pid",
        .cmp    = sort__thread_cmp,
        .print  = sort__thread_print,
+       .width  = &threads__col_width,
 };
 
 /* --sort comm */
@@ -573,16 +632,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self)
+sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
 {
-       return fprintf(fp, "%16s", self->thread->comm);
+       return repsep_fprintf(fp, "%*s", width, self->thread->comm);
 }
 
 static struct sort_entry sort_comm = {
-       .header         = "         Command",
+       .header         = "Command",
        .cmp            = sort__comm_cmp,
        .collapse       = sort__comm_collapse,
        .print          = sort__comm_print,
+       .width          = &comms__col_width,
 };
 
 /* --sort dso */
@@ -600,18 +660,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self)
+sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
 {
        if (self->dso)
-               return fprintf(fp, "%-25s", self->dso->name);
+               return repsep_fprintf(fp, "%-*s", width, self->dso->name);
 
-       return fprintf(fp, "%016llx         ", (u64)self->ip);
+       return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
 }
 
 static struct sort_entry sort_dso = {
-       .header = "Shared Object            ",
+       .header = "Shared Object",
        .cmp    = sort__dso_cmp,
        .print  = sort__dso_print,
+       .width  = &dsos__col_width,
 };
 
 /* --sort symbol */
@@ -631,18 +692,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self)
+sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
 {
        size_t ret = 0;
 
        if (verbose)
-               ret += fprintf(fp, "%#018llx  ", (u64)self->ip);
+               ret += repsep_fprintf(fp, "%#018llx  ", (u64)self->ip);
 
+       ret += repsep_fprintf(fp, "[%c] ", self->level);
        if (self->sym) {
-               ret += fprintf(fp, "[%c] %s",
-                       self->dso == kernel_dso ? 'k' : '.', self->sym->name);
+               ret += repsep_fprintf(fp, "%s", self->sym->name);
+
+               if (self->sym->module)
+                       ret += repsep_fprintf(fp, "\t[%s]",
+                                            self->sym->module->name);
        } else {
-               ret += fprintf(fp, "%#016llx", (u64)self->ip);
+               ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
        }
 
        return ret;
@@ -669,19 +734,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
-sort__parent_print(FILE *fp, struct hist_entry *self)
+sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
 {
-       size_t ret = 0;
-
-       ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
-
-       return ret;
+       return repsep_fprintf(fp, "%-*s", width,
+                             self->parent ? self->parent->name : "[other]");
 }
 
+static unsigned int parent_symbol__col_width;
+
 static struct sort_entry sort_parent = {
-       .header = "Parent symbol       ",
+       .header = "Parent symbol",
        .cmp    = sort__parent_cmp,
        .print  = sort__parent_print,
+       .width  = &parent_symbol__col_width,
 };
 
 static int sort__need_collapse = 0;
@@ -705,7 +770,7 @@ static LIST_HEAD(hist_entry__sort_list);
 
 static int sort_dimension__add(char *tok)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
                struct sort_dimension *sd = &sort_dimensions[i];
@@ -775,8 +840,109 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
        return cmp;
 }
 
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
+{
+       int i;
+       size_t ret = 0;
+
+       ret += fprintf(fp, "%s", "                ");
+
+       for (i = 0; i < depth; i++)
+               if (depth_mask & (1 << i))
+                       ret += fprintf(fp, "|          ");
+               else
+                       ret += fprintf(fp, "           ");
+
+       ret += fprintf(fp, "\n");
+
+       return ret;
+}
+static size_t
+ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
+                      int depth_mask, int count, u64 total_samples,
+                      int hits)
+{
+       int i;
+       size_t ret = 0;
+
+       ret += fprintf(fp, "%s", "                ");
+       for (i = 0; i < depth; i++) {
+               if (depth_mask & (1 << i))
+                       ret += fprintf(fp, "|");
+               else
+                       ret += fprintf(fp, " ");
+               if (!count && i == depth - 1) {
+                       double percent;
+
+                       percent = hits * 100.0 / total_samples;
+                       ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
+               } else
+                       ret += fprintf(fp, "%s", "          ");
+       }
+       if (chain->sym)
+               ret += fprintf(fp, "%s\n", chain->sym->name);
+       else
+               ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
+
+       return ret;
+}
+
+static size_t
+callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                       u64 total_samples, int depth, int depth_mask)
+{
+       struct rb_node *node, *next;
+       struct callchain_node *child;
+       struct callchain_list *chain;
+       int new_depth_mask = depth_mask;
+       u64 new_total;
+       size_t ret = 0;
+       int i;
+
+       if (callchain_param.mode == CHAIN_GRAPH_REL)
+               new_total = self->cumul_hit;
+       else
+               new_total = total_samples;
+
+       node = rb_first(&self->rb_root);
+       while (node) {
+               child = rb_entry(node, struct callchain_node, rb_node);
+
+               /*
+                * The depth mask manages the output of pipes that show
+                * the depth. We don't want to keep the pipes of the current
+                * level for the last child of this depth
+                */
+               next = rb_next(node);
+               if (!next)
+                       new_depth_mask &= ~(1 << (depth - 1));
+
+               /*
+                * But we keep the older depth mask for the line seperator
+                * to keep the level link until we reach the last child
+                */
+               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
+               i = 0;
+               list_for_each_entry(chain, &child->val, list) {
+                       if (chain->ip >= PERF_CONTEXT_MAX)
+                               continue;
+                       ret += ipchain__fprintf_graph(fp, chain, depth,
+                                                     new_depth_mask, i++,
+                                                     new_total,
+                                                     child->cumul_hit);
+               }
+               ret += callchain__fprintf_graph(fp, child, new_total,
+                                               depth + 1,
+                                               new_depth_mask | (1 << depth));
+               node = next;
+       }
+
+       return ret;
+}
+
 static size_t
-callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
+callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
+                       u64 total_samples)
 {
        struct callchain_list *chain;
        size_t ret = 0;
@@ -784,11 +950,18 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
        if (!self)
                return 0;
 
-       ret += callchain__fprintf(fp, self->parent, total_samples);
+       ret += callchain__fprintf_flat(fp, self->parent, total_samples);
 
 
-       list_for_each_entry(chain, &self->val, list)
-               ret += fprintf(fp, "                %p\n", (void *)chain->ip);
+       list_for_each_entry(chain, &self->val, list) {
+               if (chain->ip >= PERF_CONTEXT_MAX)
+                       continue;
+               if (chain->sym)
+                       ret += fprintf(fp, "                %s\n", chain->sym->name);
+               else
+                       ret += fprintf(fp, "                %p\n",
+                                       (void *)(long)chain->ip);
+       }
 
        return ret;
 }
@@ -807,8 +980,19 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
 
                chain = rb_entry(rb_node, struct callchain_node, rb_node);
                percent = chain->hit * 100.0 / total_samples;
-               ret += fprintf(fp, "           %6.2f%%\n", percent);
-               ret += callchain__fprintf(fp, chain, total_samples);
+               switch (callchain_param.mode) {
+               case CHAIN_FLAT:
+                       ret += percent_color_fprintf(fp, "           %6.2f%%\n",
+                                                    percent);
+                       ret += callchain__fprintf_flat(fp, chain, total_samples);
+                       break;
+               case CHAIN_GRAPH_ABS: /* Falldown */
+               case CHAIN_GRAPH_REL:
+                       ret += callchain__fprintf_graph(fp, chain,
+                                                       total_samples, 1, 1);
+               default:
+                       break;
+               }
                ret += fprintf(fp, "\n");
                rb_node = rb_next(rb_node);
        }
@@ -826,33 +1010,26 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
        if (exclude_other && !self->parent)
                return 0;
 
-       if (total_samples) {
-               double percent = self->count * 100.0 / total_samples;
-               char *color = PERF_COLOR_NORMAL;
-
-               /*
-                * We color high-overhead entries in red, mid-overhead
-                * entries in green - and keep the low overhead places
-                * normal:
-                */
-               if (percent >= 5.0) {
-                       color = PERF_COLOR_RED;
-               } else {
-                       if (percent >= 0.5)
-                               color = PERF_COLOR_GREEN;
-               }
+       if (total_samples)
+               ret = percent_color_fprintf(fp,
+                                           field_sep ? "%.2f" : "   %6.2f%%",
+                                       (self->count * 100.0) / total_samples);
+       else
+               ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
 
-               ret = color_fprintf(fp, color, "   %6.2f%%",
-                               (self->count * 100.0) / total_samples);
-       } else
-               ret = fprintf(fp, "%12Ld ", self->count);
+       if (show_nr_samples) {
+               if (field_sep)
+                       fprintf(fp, "%c%lld", *field_sep, self->count);
+               else
+                       fprintf(fp, "%11lld", self->count);
+       }
 
        list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (exclude_other && (se == &sort_parent))
+               if (se->elide)
                        continue;
 
-               fprintf(fp, "  ");
-               ret += se->print(fp, self);
+               fprintf(fp, "%s", field_sep ?: "  ");
+               ret += se->print(fp, self, se->width ? *se->width : 0);
        }
 
        ret += fprintf(fp, "\n");
@@ -867,6 +1044,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
  *
  */
 
+static void dso__calc_col_width(struct dso *self)
+{
+       if (!col_width_list_str && !field_sep &&
+           (!dso_list || strlist__has_entry(dso_list, self->name))) {
+               unsigned int slen = strlen(self->name);
+               if (slen > dsos__col_width)
+                       dsos__col_width = slen;
+       }
+
+       self->slen_calculated = 1;
+}
+
 static struct symbol *
 resolve_symbol(struct thread *thread, struct map **mapp,
               struct dso **dsop, u64 *ipp)
@@ -886,6 +1075,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
 
        map = thread__find_map(thread, ip);
        if (map != NULL) {
+               /*
+                * We have to do this here as we may have a dso
+                * with no symbol hit that has a name longer than
+                * the ones with symbols sampled.
+                */
+               if (!sort_dso.elide && !map->dso->slen_calculated)
+                       dso__calc_col_width(map->dso);
+
                if (mapp)
                        *mapp = map;
 got_map:
@@ -923,6 +1120,58 @@ static int call__match(struct symbol *sym)
        return 0;
 }
 
+static struct symbol **
+resolve_callchain(struct thread *thread, struct map *map __used,
+                   struct ip_callchain *chain, struct hist_entry *entry)
+{
+       u64 context = PERF_CONTEXT_MAX;
+       struct symbol **syms = NULL;
+       unsigned int i;
+
+       if (callchain) {
+               syms = calloc(chain->nr, sizeof(*syms));
+               if (!syms) {
+                       fprintf(stderr, "Can't allocate memory for symbols\n");
+                       exit(-1);
+               }
+       }
+
+       for (i = 0; i < chain->nr; i++) {
+               u64 ip = chain->ips[i];
+               struct dso *dso = NULL;
+               struct symbol *sym;
+
+               if (ip >= PERF_CONTEXT_MAX) {
+                       context = ip;
+                       continue;
+               }
+
+               switch (context) {
+               case PERF_CONTEXT_HV:
+                       dso = hypervisor_dso;
+                       break;
+               case PERF_CONTEXT_KERNEL:
+                       dso = kernel_dso;
+                       break;
+               default:
+                       break;
+               }
+
+               sym = resolve_symbol(thread, NULL, &dso, &ip);
+
+               if (sym) {
+                       if (sort__has_parent && call__match(sym) &&
+                           !entry->parent)
+                               entry->parent = sym;
+                       if (!callchain)
+                               break;
+                       syms[i] = sym;
+               }
+       }
+
+       return syms;
+}
+
 /*
  * collect histogram counts
  */
@@ -935,6 +1184,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        struct rb_node **p = &hist.rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *he;
+       struct symbol **syms = NULL;
        struct hist_entry entry = {
                .thread = thread,
                .map    = map,
@@ -948,36 +1198,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        };
        int cmp;
 
-       if (sort__has_parent && chain) {
-               u64 context = PERF_CONTEXT_MAX;
-               int i;
-
-               for (i = 0; i < chain->nr; i++) {
-                       u64 ip = chain->ips[i];
-                       struct dso *dso = NULL;
-                       struct symbol *sym;
-
-                       if (ip >= PERF_CONTEXT_MAX) {
-                               context = ip;
-                               continue;
-                       }
-
-                       switch (context) {
-                       case PERF_CONTEXT_KERNEL:
-                               dso = kernel_dso;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       sym = resolve_symbol(thread, NULL, &dso, &ip);
-
-                       if (sym && call__match(sym)) {
-                               entry.parent = sym;
-                               break;
-                       }
-               }
-       }
+       if ((sort__has_parent || callchain) && chain)
+               syms = resolve_callchain(thread, map, chain, &entry);
 
        while (*p != NULL) {
                parent = *p;
@@ -987,8 +1209,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
 
                if (!cmp) {
                        he->count += count;
-                       if (callchain)
-                               append_chain(&he->callchain, chain);
+                       if (callchain) {
+                               append_chain(&he->callchain, chain, syms);
+                               free(syms);
+                       }
                        return 0;
                }
 
@@ -1004,7 +1228,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        *he = entry;
        if (callchain) {
                callchain_init(&he->callchain);
-               append_chain(&he->callchain, chain);
+               append_chain(&he->callchain, chain, syms);
+               free(syms);
        }
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, &hist);
@@ -1076,14 +1301,15 @@ static void collapse__resort(void)
 
 static struct rb_root output_hists;
 
-static void output__insert_entry(struct hist_entry *he)
+static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
 {
        struct rb_node **p = &output_hists.rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
 
        if (callchain)
-               sort_chain_to_rbtree(&he->sorted_chain, &he->callchain);
+               callchain_param.sort(&he->sorted_chain, &he->callchain,
+                                     min_callchain_hits, &callchain_param);
 
        while (*p != NULL) {
                parent = *p;
@@ -1099,11 +1325,14 @@ static void output__insert_entry(struct hist_entry *he)
        rb_insert_color(&he->rb_node, &output_hists);
 }
 
-static void output__resort(void)
+static void output__resort(u64 total_samples)
 {
        struct rb_node *next;
        struct hist_entry *n;
        struct rb_root *tree = &hist;
+       u64 min_callchain_hits;
+
+       min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
 
        if (sort__need_collapse)
                tree = &collapse_hists;
@@ -1115,7 +1344,7 @@ static void output__resort(void)
                next = rb_next(&n->rb_node);
 
                rb_erase(&n->rb_node, tree);
-               output__insert_entry(n);
+               output__insert_entry(n, min_callchain_hits);
        }
 }
 
@@ -1125,35 +1354,67 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
        struct sort_entry *se;
        struct rb_node *nd;
        size_t ret = 0;
+       unsigned int width;
+       char *col_width = col_width_list_str;
 
-       fprintf(fp, "\n");
-       fprintf(fp, "#\n");
-       fprintf(fp, "# (%Ld samples)\n", (u64)total_samples);
+       fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
        fprintf(fp, "#\n");
 
        fprintf(fp, "# Overhead");
+       if (show_nr_samples) {
+               if (field_sep)
+                       fprintf(fp, "%cSamples", *field_sep);
+               else
+                       fputs("  Samples  ", fp);
+       }
        list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (exclude_other && (se == &sort_parent))
+               if (se->elide)
                        continue;
-               fprintf(fp, "  %s", se->header);
+               if (field_sep) {
+                       fprintf(fp, "%c%s", *field_sep, se->header);
+                       continue;
+               }
+               width = strlen(se->header);
+               if (se->width) {
+                       if (col_width_list_str) {
+                               if (col_width) {
+                                       *se->width = atoi(col_width);
+                                       col_width = strchr(col_width, ',');
+                                       if (col_width)
+                                               ++col_width;
+                               }
+                       }
+                       width = *se->width = max(*se->width, width);
+               }
+               fprintf(fp, "  %*s", width, se->header);
        }
        fprintf(fp, "\n");
 
+       if (field_sep)
+               goto print_entries;
+
        fprintf(fp, "# ........");
+       if (show_nr_samples)
+               fprintf(fp, " ..........");
        list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int i;
+               unsigned int i;
 
-               if (exclude_other && (se == &sort_parent))
+               if (se->elide)
                        continue;
 
                fprintf(fp, "  ");
-               for (i = 0; i < strlen(se->header); i++)
+               if (se->width)
+                       width = *se->width;
+               else
+                       width = strlen(se->header);
+               for (i = 0; i < width; i++)
                        fprintf(fp, ".");
        }
        fprintf(fp, "\n");
 
        fprintf(fp, "#\n");
 
+print_entries:
        for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
                pos = rb_entry(nd, struct hist_entry, rb_node);
                ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1213,6 +1474,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        struct map *map = NULL;
        void *more_data = event->ip.__more_data;
        struct ip_callchain *chain = NULL;
+       int cpumode;
 
        if (sample_type & PERF_SAMPLE_PERIOD) {
                period = *(u64 *)more_data;
@@ -1228,7 +1490,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                (long long)period);
 
        if (sample_type & PERF_SAMPLE_CALLCHAIN) {
-               int i;
+               unsigned int i;
 
                chain = (void *)more_data;
 
@@ -1256,7 +1518,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        if (comm_list && !strlist__has_entry(comm_list, thread->comm))
                return 0;
 
-       if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
+       cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
+
+       if (cpumode == PERF_EVENT_MISC_KERNEL) {
                show = SHOW_KERNEL;
                level = 'k';
 
@@ -1264,7 +1528,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 
                dprintf(" ...... dso: %s\n", dso->name);
 
-       } else if (event->header.misc & PERF_EVENT_MISC_USER) {
+       } else if (cpumode == PERF_EVENT_MISC_USER) {
 
                show = SHOW_USER;
                level = '.';
@@ -1272,6 +1536,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        } else {
                show = SHOW_HV;
                level = 'H';
+
+               dso = hypervisor_dso;
+
                dprintf(" ...... dso: [hypervisor]\n");
        }
 
@@ -1360,19 +1627,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static int
-process_period_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->period.time,
-               event->period.id,
-               event->period.sample_period);
-
-       return 0;
-}
-
 static int
 process_lost_event(event_t *event, unsigned long offset, unsigned long head)
 {
@@ -1454,9 +1708,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        case PERF_EVENT_FORK:
                return process_fork_event(event, offset, head);
 
-       case PERF_EVENT_PERIOD:
-               return process_period_event(event, offset, head);
-
        case PERF_EVENT_LOST:
                return process_lost_event(event, offset, head);
 
@@ -1534,9 +1785,19 @@ static int __cmd_report(void)
 
        sample_type = perf_header__sample_type();
 
-       if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
-               fprintf(stderr, "selected --sort parent, but no callchain data\n");
-               exit(-1);
+       if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+               if (sort__has_parent) {
+                       fprintf(stderr, "selected --sort parent, but no"
+                                       " callchain data. Did you call"
+                                       " perf record without -g?\n");
+                       exit(-1);
+               }
+               if (callchain) {
+                       fprintf(stderr, "selected -c but no callchain data."
+                                       " Did you call perf record without"
+                                       " -g?\n");
+                       exit(-1);
+               }
        }
 
        if (load_kernel() < 0) {
@@ -1619,7 +1880,7 @@ more:
        if (offset + head >= header->data_offset + header->data_size)
                goto done;
 
-       if (offset + head < stat.st_size)
+       if (offset + head < (unsigned long)stat.st_size)
                goto more;
 
 done:
@@ -1643,12 +1904,58 @@ done:
                dsos__fprintf(stdout);
 
        collapse__resort();
-       output__resort();
+       output__resort(total);
        output__fprintf(stdout, total);
 
        return rc;
 }
 
+static int
+parse_callchain_opt(const struct option *opt __used, const char *arg,
+                   int unset __used)
+{
+       char *tok;
+       char *endptr;
+
+       callchain = 1;
+
+       if (!arg)
+               return 0;
+
+       tok = strtok((char *)arg, ",");
+       if (!tok)
+               return -1;
+
+       /* get the output mode */
+       if (!strncmp(tok, "graph", strlen(arg)))
+               callchain_param.mode = CHAIN_GRAPH_ABS;
+
+       else if (!strncmp(tok, "flat", strlen(arg)))
+               callchain_param.mode = CHAIN_FLAT;
+
+       else if (!strncmp(tok, "fractal", strlen(arg)))
+               callchain_param.mode = CHAIN_GRAPH_REL;
+
+       else
+               return -1;
+
+       /* get the min percentage */
+       tok = strtok(NULL, ",");
+       if (!tok)
+               goto setup;
+
+       callchain_param.min_percent = strtod(tok, &endptr);
+       if (tok == endptr)
+               return -1;
+
+setup:
+       if (register_callchain_param(&callchain_param) < 0) {
+               fprintf(stderr, "Can't register callchain params\n");
+               return -1;
+       }
+       return 0;
+}
+
 static const char * const report_usage[] = {
        "perf report [<options>] <command>",
        NULL
@@ -1662,6 +1969,10 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &modules,
+                   "load module symbols - WARNING: use only with -k and LIVE kernel"),
+       OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
+                   "Show a column with the number of samples"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1670,13 +1981,21 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &exclude_other,
                    "Only display entries with parent-match"),
-       OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"),
+       OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
+                    "Display callchains using output_type and min percent threshold. "
+                    "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
        OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
                   "only consider symbols in these dsos"),
        OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
                   "only consider symbols in these comms"),
        OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
                   "only consider these symbols"),
+       OPT_STRING('w', "column-widths", &col_width_list_str,
+                  "width[,width...]",
+                  "don't try to adjust column width, use these fixed values"),
+       OPT_STRING('t', "field-separator", &field_sep, "separator",
+                  "separator for columns, no spaces will be added between "
+                  "columns '.' is reserved."),
        OPT_END()
 };
 
@@ -1696,7 +2015,8 @@ static void setup_sorting(void)
 }
 
 static void setup_list(struct strlist **list, const char *list_str,
-                      const char *list_name)
+                      struct sort_entry *se, const char *list_name,
+                      FILE *fp)
 {
        if (list_str) {
                *list = strlist__new(true, list_str);
@@ -1705,10 +2025,15 @@ static void setup_list(struct strlist **list, const char *list_str,
                                list_name);
                        exit(129);
                }
+               if (strlist__nr_entries(*list) == 1) {
+                       fprintf(fp, "# %s: %s\n", list_name,
+                               strlist__entry(*list, 0)->s);
+                       se->elide = true;
+               }
        }
 }
 
-int cmd_report(int argc, const char **argv, const char *prefix)
+int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
        symbol__init();
 
@@ -1718,9 +2043,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
 
        setup_sorting();
 
-       if (parent_pattern != default_parent_pattern)
+       if (parent_pattern != default_parent_pattern) {
                sort_dimension__add("parent");
-       else
+               sort_parent.elide = 1;
+       } else
                exclude_other = 0;
 
        /*
@@ -1729,11 +2055,17 @@ int cmd_report(int argc, const char **argv, const char *prefix)
        if (argc)
                usage_with_options(report_usage, options);
 
-       setup_list(&dso_list, dso_list_str, "dso");
-       setup_list(&comm_list, comm_list_str, "comm");
-       setup_list(&sym_list, sym_list_str, "symbol");
-
        setup_pager();
 
+       setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
+       setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
+       setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
+
+       if (field_sep && *field_sep == '.') {
+               fputs("'.' is the only non valid --field-separator argument\n",
+                     stderr);
+               exit(129);
+       }
+
        return __cmd_report();
 }
index 2e03524a1de0a863c85be35553b66415ab502569..f9510eeeb6c7a3f7e832abecbc77d102644c6141 100644 (file)
@@ -64,7 +64,7 @@ static struct perf_counter_attr default_attrs[] = {
 
 static int                     system_wide                     =  0;
 static int                     verbose                         =  0;
-static int                     nr_cpus                         =  0;
+static unsigned int            nr_cpus                         =  0;
 static int                     run_idx                         =  0;
 
 static int                     run_count                       =  1;
@@ -96,6 +96,10 @@ static u64                   walltime_nsecs_noise;
 static u64                     runtime_cycles_avg;
 static u64                     runtime_cycles_noise;
 
+#define MATCH_EVENT(t, c, counter)                     \
+       (attrs[counter].type == PERF_TYPE_##t &&        \
+        attrs[counter].config == PERF_COUNT_##c)
+
 #define ERR_PERF_OPEN \
 "Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
 
@@ -108,7 +112,8 @@ static void create_perf_stat_counter(int counter, int pid)
                                    PERF_FORMAT_TOTAL_TIME_RUNNING;
 
        if (system_wide) {
-               int cpu;
+               unsigned int cpu;
+
                for (cpu = 0; cpu < nr_cpus; cpu++) {
                        fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
                        if (fd[cpu][counter] < 0 && verbose)
@@ -132,13 +137,8 @@ static void create_perf_stat_counter(int counter, int pid)
  */
 static inline int nsec_counter(int counter)
 {
-       if (attrs[counter].type != PERF_TYPE_SOFTWARE)
-               return 0;
-
-       if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
-               return 1;
-
-       if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
+       if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
+           MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
                return 1;
 
        return 0;
@@ -150,8 +150,8 @@ static inline int nsec_counter(int counter)
 static void read_counter(int counter)
 {
        u64 *count, single_count[3];
-       ssize_t res;
-       int cpu, nv;
+       unsigned int cpu;
+       size_t res, nv;
        int scaled;
 
        count = event_res[run_idx][counter];
@@ -165,6 +165,7 @@ static void read_counter(int counter)
 
                res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
                assert(res == nv * sizeof(u64));
+
                close(fd[cpu][counter]);
                fd[cpu][counter] = -1;
 
@@ -192,15 +193,13 @@ static void read_counter(int counter)
        /*
         * Save the full runtime - to allow normalization during printout:
         */
-       if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
-               attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
+       if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
                runtime_nsecs[run_idx] = count[0];
-       if (attrs[counter].type == PERF_TYPE_HARDWARE &&
-               attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES)
+       if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
                runtime_cycles[run_idx] = count[0];
 }
 
-static int run_perf_stat(int argc, const char **argv)
+static int run_perf_stat(int argc __used, const char **argv)
 {
        unsigned long long t0, t1;
        int status = 0;
@@ -240,7 +239,8 @@ static int run_perf_stat(int argc, const char **argv)
                /*
                 * Wait until the parent tells us to go.
                 */
-               read(go_pipe[0], &buf, 1);
+               if (read(go_pipe[0], &buf, 1) == -1)
+                       perror("unable to read pipe");
 
                execvp(argv[0], (char **)argv);
 
@@ -253,7 +253,8 @@ static int run_perf_stat(int argc, const char **argv)
         */
        close(child_ready_pipe[1]);
        close(go_pipe[0]);
-       read(child_ready_pipe[0], &buf, 1);
+       if (read(child_ready_pipe[0], &buf, 1) == -1)
+               perror("unable to read pipe");
        close(child_ready_pipe[0]);
 
        for (counter = 0; counter < nr_counters; counter++)
@@ -290,9 +291,7 @@ static void nsec_printout(int counter, u64 *count, u64 *noise)
 
        fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
 
-       if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
-               attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
-
+       if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
                if (walltime_nsecs_avg)
                        fprintf(stderr, " # %10.3f CPUs ",
                                (double)count[0] / (double)walltime_nsecs_avg);
@@ -305,9 +304,7 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
        fprintf(stderr, " %14Ld  %-24s", count[0], event_name(counter));
 
        if (runtime_cycles_avg &&
-               attrs[counter].type == PERF_TYPE_HARDWARE &&
-                       attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
-
+           MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
                fprintf(stderr, " # %10.3f IPC  ",
                        (double)count[0] / (double)runtime_cycles_avg);
        } else {
@@ -390,7 +387,7 @@ static void calc_avg(void)
                                event_res_avg[j]+1, event_res[i][j]+1);
                        update_avg("counter/2", j,
                                event_res_avg[j]+2, event_res[i][j]+2);
-                       if (event_scaled[i][j] != -1)
+                       if (event_scaled[i][j] != (u64)-1)
                                update_avg("scaled", j,
                                        event_scaled_avg + j, event_scaled[i]+j);
                        else
@@ -510,11 +507,12 @@ static const struct option options[] = {
        OPT_END()
 };
 
-int cmd_stat(int argc, const char **argv, const char *prefix)
+int cmd_stat(int argc, const char **argv, const char *prefix __used)
 {
        int status;
 
-       argc = parse_options(argc, argv, options, stat_usage, 0);
+       argc = parse_options(argc, argv, options, stat_usage,
+               PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc)
                usage_with_options(stat_usage, options);
        if (run_count <= 0 || run_count > MAX_RUN)
@@ -528,7 +526,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
 
        nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
        assert(nr_cpus <= MAX_NR_CPUS);
-       assert(nr_cpus >= 0);
+       assert((int)nr_cpus >= 0);
 
        /*
         * We dont want to block the signals - that would cause
index cf0d21f1ae10e8917809519942b010cdf8d6d64a..c0a423004e153b83249fb1d6631a5499e4375dc5 100644 (file)
@@ -23,7 +23,7 @@
 #include "util/symbol.h"
 #include "util/color.h"
 #include "util/util.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
@@ -58,6 +58,7 @@ static u64                    count_filter                    =  5;
 static int                     print_entries                   = 15;
 
 static int                     target_pid                      = -1;
+static int                     inherit                         =  0;
 static int                     profile_cpu                     = -1;
 static int                     nr_cpus                         =  0;
 static unsigned int            realtime_prio                   =  0;
@@ -66,6 +67,7 @@ static unsigned int           page_size;
 static unsigned int            mmap_pages                      = 16;
 static int                     freq                            =  0;
 static int                     verbose                         =  0;
+static char                    *vmlinux                        =  NULL;
 
 static char                    *sym_filter;
 static unsigned long           filter_start;
@@ -238,7 +240,6 @@ static void print_sym_table(void)
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
                struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
                struct symbol *sym = (struct symbol *)(syme + 1);
-               char *color = PERF_COLOR_NORMAL;
                double pcnt;
 
                if (++printed > print_entries || syme->snap_count < count_filter)
@@ -247,29 +248,20 @@ static void print_sym_table(void)
                pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
                                         sum_ksamples));
 
-               /*
-                * We color high-overhead entries in red, mid-overhead
-                * entries in green - and keep the low overhead places
-                * normal:
-                */
-               if (pcnt >= 5.0) {
-                       color = PERF_COLOR_RED;
-               } else {
-                       if (pcnt >= 0.5)
-                               color = PERF_COLOR_GREEN;
-               }
-
                if (nr_counters == 1)
                        printf("%20.2f - ", syme->weight);
                else
                        printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
 
-               color_fprintf(stdout, color, "%4.1f%%", pcnt);
-               printf(" - %016llx : %s\n", sym->start, sym->name);
+               percent_color_fprintf(stdout, "%4.1f%%", pcnt);
+               printf(" - %016llx : %s", sym->start, sym->name);
+               if (sym->module)
+                       printf("\t[%s]", sym->module->name);
+               printf("\n");
        }
 }
 
-static void *display_thread(void *arg)
+static void *display_thread(void *arg __used)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
        int delay_msecs = delay_secs * 1000;
@@ -286,11 +278,31 @@ static void *display_thread(void *arg)
        return NULL;
 }
 
+/* Tag samples to be skipped. */
+static const char *skip_symbols[] = {
+       "default_idle",
+       "cpu_idle",
+       "enter_idle",
+       "exit_idle",
+       "mwait_idle",
+       "ppc64_runlatch_off",
+       "pseries_dedicated_idle_sleep",
+       NULL
+};
+
 static int symbol_filter(struct dso *self, struct symbol *sym)
 {
        static int filter_match;
        struct sym_entry *syme;
        const char *name = sym->name;
+       int i;
+
+       /*
+        * ppc64 uses function descriptors and appends a '.' to the
+        * start of every instruction address. Remove it.
+        */
+       if (name[0] == '.')
+               name++;
 
        if (!strcmp(name, "_text") ||
            !strcmp(name, "_etext") ||
@@ -302,13 +314,12 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
                return 1;
 
        syme = dso__sym_priv(self, sym);
-       /* Tag samples to be skipped. */
-       if (!strcmp("default_idle", name) ||
-           !strcmp("cpu_idle", name) ||
-           !strcmp("enter_idle", name) ||
-           !strcmp("exit_idle", name) ||
-           !strcmp("mwait_idle", name))
-               syme->skip = 1;
+       for (i = 0; skip_symbols[i]; i++) {
+               if (!strcmp(skip_symbols[i], name)) {
+                       syme->skip = 1;
+                       break;
+               }
+       }
 
        if (filter_match == 1) {
                filter_end = sym->start;
@@ -340,12 +351,13 @@ static int parse_symbols(void)
 {
        struct rb_node *node;
        struct symbol  *sym;
+       int modules = vmlinux ? 1 : 0;
 
        kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
        if (kernel_dso == NULL)
                return -1;
 
-       if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0)
+       if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
                goto out_delete_dso;
 
        node = rb_first(&kernel_dso->syms);
@@ -407,7 +419,7 @@ static void process_event(u64 ip, int counter, int user)
 struct mmap_data {
        int                     counter;
        void                    *base;
-       unsigned int            mask;
+       int                     mask;
        unsigned int            prev;
 };
 
@@ -538,7 +550,7 @@ int group_fd;
 static void start_counter(int i, int counter)
 {
        struct perf_counter_attr *attr;
-       unsigned int cpu;
+       int cpu;
 
        cpu = profile_cpu;
        if (target_pid == -1 && profile_cpu == -1)
@@ -548,6 +560,7 @@ static void start_counter(int i, int counter)
 
        attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
        attr->freq              = freq;
+       attr->inherit           = (cpu < 0) && inherit;
 
 try_again:
        fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
@@ -661,6 +674,7 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
+       OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
                    "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -673,9 +687,11 @@ static const struct option options[] = {
                    "only display functions with more events than this"),
        OPT_BOOLEAN('g', "group", &group,
                            "put the counters into a counter group"),
+       OPT_BOOLEAN('i', "inherit", &inherit,
+                   "child tasks inherit counters"),
        OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
                    "only display symbols matchig this pattern"),
-       OPT_BOOLEAN('z', "zero", &group,
+       OPT_BOOLEAN('z', "zero", &zero,
                    "zero history across updates"),
        OPT_INTEGER('F', "freq", &freq,
                    "profile at this frequency"),
@@ -686,10 +702,12 @@ static const struct option options[] = {
        OPT_END()
 };
 
-int cmd_top(int argc, const char **argv, const char *prefix)
+int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
+       symbol__init();
+
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);
index 4eb725933703b6e8c41c558e46f11d705cc9d41f..31982ad064b4781c7b78dd5f9ef32f3f29dd3523 100644 (file)
@@ -12,6 +12,8 @@
 #include "util/cache.h"
 #include "util/quote.h"
 #include "util/run-command.h"
+#include "util/parse-events.h"
+#include "util/string.h"
 
 const char perf_usage_string[] =
        "perf [--version] [--help] COMMAND [ARGS]";
@@ -25,6 +27,8 @@ struct pager_config {
        int val;
 };
 
+static char debugfs_mntpt[MAXPATHLEN];
+
 static int pager_command_config(const char *var, const char *value, void *data)
 {
        struct pager_config *c = data;
@@ -56,6 +60,15 @@ static void commit_pager_choice(void) {
        }
 }
 
+static void set_debugfs_path(void)
+{
+       char *path;
+
+       path = getenv(PERF_DEBUGFS_ENVIRONMENT);
+       snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
+                "tracing/events");
+}
+
 static int handle_options(const char*** argv, int* argc, int* envchanged)
 {
        int handled = 0;
@@ -122,6 +135,22 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
                        setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
                        if (envchanged)
                                *envchanged = 1;
+               } else if (!strcmp(cmd, "--debugfs-dir")) {
+                       if (*argc < 2) {
+                               fprintf(stderr, "No directory given for --debugfs-dir.\n");
+                               usage(perf_usage_string);
+                       }
+                       strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
+                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       if (envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
+               } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
+                       strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
+                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(perf_usage_string);
@@ -228,9 +257,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        if (use_pager == -1 && p->option & USE_PAGER)
                use_pager = 1;
        commit_pager_choice();
-
-       if (p->option & NEED_WORK_TREE)
-               /* setup_work_tree() */;
+       set_debugfs_path();
 
        status = p->fn(argc, argv, prefix);
        if (status)
@@ -266,7 +293,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "annotate", cmd_annotate, 0 },
                { "version", cmd_version, 0 },
        };
-       int i;
+       unsigned int i;
        static const char ext[] = STRIP_EXTENSION;
 
        if (sizeof(ext) > 1) {
@@ -349,6 +376,49 @@ static int run_argv(int *argcp, const char ***argv)
        return done_alias;
 }
 
+/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
+static void get_debugfs_mntpt(void)
+{
+       FILE *file;
+       char fs_type[100];
+       char debugfs[MAXPATHLEN];
+
+       /*
+        * try the standard location
+        */
+       if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
+               strcpy(debugfs_mntpt, "/sys/kernel/debug/");
+               return;
+       }
+
+       /*
+        * try the sane location
+        */
+       if (valid_debugfs_mount("/debug/") == 0) {
+               strcpy(debugfs_mntpt, "/debug/");
+               return;
+       }
+
+       /*
+        * give up and parse /proc/mounts
+        */
+       file = fopen("/proc/mounts", "r");
+       if (file == NULL)
+               return;
+
+       while (fscanf(file, "%*s %"
+                     STR(MAXPATHLEN)
+                     "s %99s %*s %*d %*d\n",
+                     debugfs, fs_type) == 2) {
+               if (strcmp(fs_type, "debugfs") == 0)
+                       break;
+       }
+       fclose(file);
+       if (strcmp(fs_type, "debugfs") == 0) {
+               strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
+               debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+       }
+}
 
 int main(int argc, const char **argv)
 {
@@ -357,7 +427,8 @@ int main(int argc, const char **argv)
        cmd = perf_extract_argv0_path(argv[0]);
        if (!cmd)
                cmd = "perf-help";
-
+       /* get debugfs mount point from /proc/mounts */
+       get_debugfs_mntpt();
        /*
         * "perf-xxxx" is the same as "perf xxxx", but we obviously:
         *
@@ -380,6 +451,7 @@ int main(int argc, const char **argv)
        argc--;
        handle_options(&argv, &argc, NULL);
        commit_pager_choice();
+       set_debugfs_path();
        if (argc > 0) {
                if (!prefixcmp(argv[0], "--"))
                        argv[0] += 2;
index d3042a6ba03dad7ec58fddfaf6e1a95482c16110..e5148e2b6134242f3b42c3dd59fafd54a7acb60f 100644 (file)
@@ -1,7 +1,13 @@
 #ifndef _PERF_PERF_H
 #define _PERF_PERF_H
 
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__i386__)
+#include "../../arch/x86/include/asm/unistd.h"
+#define rmb()          asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
+#define cpu_relax()    asm volatile("rep; nop" ::: "memory");
+#endif
+
+#if defined(__x86_64__)
 #include "../../arch/x86/include/asm/unistd.h"
 #define rmb()          asm volatile("lfence" ::: "memory")
 #define cpu_relax()    asm volatile("rep; nop" ::: "memory");
@@ -68,6 +74,8 @@ static inline unsigned long long rdclock(void)
 #define __user
 #define asmlinkage
 
+#define __used         __attribute__((__unused__))
+
 #define unlikely(x)    __builtin_expect(!!(x), 0)
 #define min(x, y) ({                           \
        typeof(x) _min1 = (x);                  \
index 9b3dd2b428df8c4e95ed0dce7e281419744cf14e..b8144e80bb1e5b436d95f1c96757fe34b9451946 100644 (file)
@@ -3,7 +3,7 @@
 static const char *alias_key;
 static char *alias_val;
 
-static int alias_lookup_cb(const char *k, const char *v, void *cb)
+static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
 {
        if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
                if (!v)
index 393d6146d13b38743641adb819c2552a56716043..4b50c412b9c574ecafc10c1c4cbaa48d8535194e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "util.h"
 #include "strbuf.h"
+#include "../perf.h"
 
 #define PERF_DIR_ENVIRONMENT "PERF_DIR"
 #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
@@ -17,6 +18,7 @@
 #define PERFATTRIBUTES_FILE ".perfattributes"
 #define INFOATTRIBUTES_FILE "info/attributes"
 #define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
index ad3c2857896117f59d82e7b691e7b391cae6090d..9d3c8141b8c158cf80a4028acabc81c1c9895336 100644 (file)
@@ -4,6 +4,9 @@
  * Handle the callchains from the stream in an ad-hoc radix tree and then
  * sort them in an rbtree.
  *
+ * Using a radix for code path provides a fast retrieval and factorizes
+ * memory use. Also that lets us use the paths in a hierarchical graph view.
+ *
  */
 
 #include <stdlib.h>
 
 #include "callchain.h"
 
+#define chain_for_each_child(child, parent)    \
+       list_for_each_entry(child, &parent->children, brothers)
 
-static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
+static void
+rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
+                   enum chain_mode mode)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
@@ -24,32 +31,125 @@ static void rb_insert_callchain(struct rb_root *root, struct callchain_node *cha
                parent = *p;
                rnode = rb_entry(parent, struct callchain_node, rb_node);
 
-               if (rnode->hit < chain->hit)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
+               switch (mode) {
+               case CHAIN_FLAT:
+                       if (rnode->hit < chain->hit)
+                               p = &(*p)->rb_left;
+                       else
+                               p = &(*p)->rb_right;
+                       break;
+               case CHAIN_GRAPH_ABS: /* Falldown */
+               case CHAIN_GRAPH_REL:
+                       if (rnode->cumul_hit < chain->cumul_hit)
+                               p = &(*p)->rb_left;
+                       else
+                               p = &(*p)->rb_right;
+                       break;
+               default:
+                       break;
+               }
        }
 
        rb_link_node(&chain->rb_node, parent, p);
        rb_insert_color(&chain->rb_node, root);
 }
 
+static void
+__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+                 u64 min_hit)
+{
+       struct callchain_node *child;
+
+       chain_for_each_child(child, node)
+               __sort_chain_flat(rb_root, child, min_hit);
+
+       if (node->hit && node->hit >= min_hit)
+               rb_insert_callchain(rb_root, node, CHAIN_FLAT);
+}
+
 /*
  * Once we get every callchains from the stream, we can now
  * sort them by hit
  */
-void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node)
+static void
+sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+               u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_flat(rb_root, node, min_hit);
+}
+
+static void __sort_chain_graph_abs(struct callchain_node *node,
+                                  u64 min_hit)
+{
+       struct callchain_node *child;
+
+       node->rb_root = RB_ROOT;
+
+       chain_for_each_child(child, node) {
+               __sort_chain_graph_abs(child, min_hit);
+               if (child->cumul_hit >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_ABS);
+       }
+}
+
+static void
+sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_graph_abs(chain_root, min_hit);
+       rb_root->rb_node = chain_root->rb_root.rb_node;
+}
+
+static void __sort_chain_graph_rel(struct callchain_node *node,
+                                  double min_percent)
 {
        struct callchain_node *child;
+       u64 min_hit;
 
-       list_for_each_entry(child, &node->children, brothers)
-               sort_chain_to_rbtree(rb_root, child);
+       node->rb_root = RB_ROOT;
+       min_hit = node->cumul_hit * min_percent / 100.0;
 
-       if (node->hit)
-               rb_insert_callchain(rb_root, node);
+       chain_for_each_child(child, node) {
+               __sort_chain_graph_rel(child, min_percent);
+               if (child->cumul_hit >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_REL);
+       }
 }
 
-static struct callchain_node *create_child(struct callchain_node *parent)
+static void
+sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit __used, struct callchain_param *param)
+{
+       __sort_chain_graph_rel(chain_root, param->min_percent);
+       rb_root->rb_node = chain_root->rb_root.rb_node;
+}
+
+int register_callchain_param(struct callchain_param *param)
+{
+       switch (param->mode) {
+       case CHAIN_GRAPH_ABS:
+               param->sort = sort_chain_graph_abs;
+               break;
+       case CHAIN_GRAPH_REL:
+               param->sort = sort_chain_graph_rel;
+               break;
+       case CHAIN_FLAT:
+               param->sort = sort_chain_flat;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Create a child for a parent. If inherit_children, then the new child
+ * will become the new parent of it's parent children
+ */
+static struct callchain_node *
+create_child(struct callchain_node *parent, bool inherit_children)
 {
        struct callchain_node *new;
 
@@ -61,91 +161,147 @@ static struct callchain_node *create_child(struct callchain_node *parent)
        new->parent = parent;
        INIT_LIST_HEAD(&new->children);
        INIT_LIST_HEAD(&new->val);
+
+       if (inherit_children) {
+               struct callchain_node *next;
+
+               list_splice(&parent->children, &new->children);
+               INIT_LIST_HEAD(&parent->children);
+
+               chain_for_each_child(next, new)
+                       next->parent = new;
+       }
        list_add_tail(&new->brothers, &parent->children);
 
        return new;
 }
 
+/*
+ * Fill the node with callchain values
+ */
 static void
-fill_node(struct callchain_node *node, struct ip_callchain *chain, int start)
+fill_node(struct callchain_node *node, struct ip_callchain *chain,
+         int start, struct symbol **syms)
 {
-       int i;
+       unsigned int i;
 
        for (i = start; i < chain->nr; i++) {
                struct callchain_list *call;
 
-               call = malloc(sizeof(*chain));
+               call = malloc(sizeof(*call));
                if (!call) {
                        perror("not enough memory for the code path tree");
                        return;
                }
                call->ip = chain->ips[i];
+               call->sym = syms[i];
                list_add_tail(&call->list, &node->val);
        }
-       node->val_nr = i - start;
+       node->val_nr = chain->nr - start;
+       if (!node->val_nr)
+               printf("Warning: empty node in callchain tree\n");
 }
 
-static void add_child(struct callchain_node *parent, struct ip_callchain *chain)
+static void
+add_child(struct callchain_node *parent, struct ip_callchain *chain,
+         int start, struct symbol **syms)
 {
        struct callchain_node *new;
 
-       new = create_child(parent);
-       fill_node(new, chain, parent->val_nr);
+       new = create_child(parent, false);
+       fill_node(new, chain, start, syms);
 
-       new->hit = 1;
+       new->cumul_hit = new->hit = 1;
 }
 
+/*
+ * Split the parent in two parts (a new child is created) and
+ * give a part of its callchain to the created child.
+ * Then create another child to host the given callchain of new branch
+ */
 static void
 split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
-               struct callchain_list *to_split, int idx)
+               struct callchain_list *to_split, int idx_parents, int idx_local,
+               struct symbol **syms)
 {
        struct callchain_node *new;
+       struct list_head *old_tail;
+       unsigned int idx_total = idx_parents + idx_local;
 
        /* split */
-       new = create_child(parent);
-       list_move_tail(&to_split->list, &new->val);
-       new->hit = parent->hit;
-       parent->hit = 0;
-       parent->val_nr = idx;
+       new = create_child(parent, true);
 
-       /* create the new one */
-       add_child(parent, chain);
+       /* split the callchain and move a part to the new child */
+       old_tail = parent->val.prev;
+       list_del_range(&to_split->list, old_tail);
+       new->val.next = &to_split->list;
+       new->val.prev = old_tail;
+       to_split->list.prev = &new->val;
+       old_tail->next = &new->val;
+
+       /* split the hits */
+       new->hit = parent->hit;
+       new->cumul_hit = parent->cumul_hit;
+       new->val_nr = parent->val_nr - idx_local;
+       parent->val_nr = idx_local;
+
+       /* create a new child for the new branch if any */
+       if (idx_total < chain->nr) {
+               parent->hit = 0;
+               add_child(parent, chain, idx_total, syms);
+       } else {
+               parent->hit = 1;
+       }
 }
 
 static int
 __append_chain(struct callchain_node *root, struct ip_callchain *chain,
-               int start);
+              unsigned int start, struct symbol **syms);
 
-static int
-__append_chain_children(struct callchain_node *root, struct ip_callchain *chain)
+static void
+__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
+                       struct symbol **syms, unsigned int start)
 {
        struct callchain_node *rnode;
 
        /* lookup in childrens */
-       list_for_each_entry(rnode, &root->children, brothers) {
-               int ret = __append_chain(rnode, chain, root->val_nr);
+       chain_for_each_child(rnode, root) {
+               unsigned int ret = __append_chain(rnode, chain, start, syms);
+
                if (!ret)
-                       return 0;
+                       goto cumul;
        }
-       return -1;
+       /* nothing in children, add to the current node */
+       add_child(root, chain, start, syms);
+
+cumul:
+       root->cumul_hit++;
 }
 
 static int
 __append_chain(struct callchain_node *root, struct ip_callchain *chain,
-               int start)
+              unsigned int start, struct symbol **syms)
 {
        struct callchain_list *cnode;
-       int i = start;
+       unsigned int i = start;
        bool found = false;
 
-       /* lookup in the current node */
+       /*
+        * Lookup in the current node
+        * If we have a symbol, then compare the start to match
+        * anywhere inside a function.
+        */
        list_for_each_entry(cnode, &root->val, list) {
-               if (cnode->ip != chain->ips[i++])
+               if (i == chain->nr)
+                       break;
+               if (cnode->sym && syms[i]) {
+                       if (cnode->sym->start != syms[i]->start)
+                               break;
+               } else if (cnode->ip != chain->ips[i])
                        break;
                if (!found)
                        found = true;
-               if (i == chain->nr)
-                       break;
+               i++;
        }
 
        /* matches not, relay on the parent */
@@ -153,22 +309,27 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
                return -1;
 
        /* we match only a part of the node. Split it and add the new chain */
-       if (i < root->val_nr) {
-               split_add_child(root, chain, cnode, i);
+       if (i - start < root->val_nr) {
+               split_add_child(root, chain, cnode, start, i - start, syms);
                return 0;
        }
 
        /* we match 100% of the path, increment the hit */
-       if (i == root->val_nr) {
+       if (i - start == root->val_nr && i == chain->nr) {
                root->hit++;
+               root->cumul_hit++;
+
                return 0;
        }
 
-       return __append_chain_children(root, chain);
+       /* We match the node and still have a part remaining */
+       __append_chain_children(root, chain, syms, i);
+
+       return 0;
 }
 
-void append_chain(struct callchain_node *root, struct ip_callchain *chain)
+void append_chain(struct callchain_node *root, struct ip_callchain *chain,
+                 struct symbol **syms)
 {
-       if (__append_chain_children(root, chain) == -1)
-               add_child(root, chain);
+       __append_chain_children(root, chain, syms, 0);
 }
index fa1cd2f71fd3bd562f821351c186fc8eb1009677..7812122bea1d50c2518c050b0db434ffa5b34826 100644 (file)
@@ -2,22 +2,42 @@
 #define __PERF_CALLCHAIN_H
 
 #include "../perf.h"
-#include "list.h"
-#include "rbtree.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include "symbol.h"
 
+enum chain_mode {
+       CHAIN_FLAT,
+       CHAIN_GRAPH_ABS,
+       CHAIN_GRAPH_REL
+};
 
 struct callchain_node {
        struct callchain_node   *parent;
        struct list_head        brothers;
-       struct list_head        children;
-       struct list_head        val;
-       struct rb_node          rb_node;
-       int                     val_nr;
-       int                     hit;
+       struct list_head        children;
+       struct list_head        val;
+       struct rb_node          rb_node; /* to sort nodes in an rbtree */
+       struct rb_root          rb_root; /* sorted tree of children */
+       unsigned int            val_nr;
+       u64                     hit;
+       u64                     cumul_hit; /* hit + hits of children */
+};
+
+struct callchain_param;
+
+typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
+                                u64, struct callchain_param *);
+
+struct callchain_param {
+       enum chain_mode         mode;
+       double                  min_percent;
+       sort_chain_func_t       sort;
 };
 
 struct callchain_list {
-       unsigned long           ip;
+       u64                     ip;
+       struct symbol           *sym;
        struct list_head        list;
 };
 
@@ -28,6 +48,7 @@ static inline void callchain_init(struct callchain_node *node)
        INIT_LIST_HEAD(&node->val);
 }
 
-void append_chain(struct callchain_node *root, struct ip_callchain *chain);
-void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node);
+int register_callchain_param(struct callchain_param *param);
+void append_chain(struct callchain_node *root, struct ip_callchain *chain,
+                 struct symbol **syms);
 #endif
index 9a8c20ccc53e28dd99ab6bd2f27f548fe85532fe..90a044d1fe7dffe526a50d8afdb5ac888ff31209 100644 (file)
@@ -11,7 +11,8 @@ static int parse_color(const char *name, int len)
        };
        char *end;
        int i;
-       for (i = 0; i < ARRAY_SIZE(color_names); i++) {
+
+       for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
                const char *str = color_names[i];
                if (!strncasecmp(name, str, len) && !str[len])
                        return i - 1;
@@ -28,7 +29,8 @@ static int parse_attr(const char *name, int len)
        static const char * const attr_names[] = {
                "bold", "dim", "ul", "blink", "reverse"
        };
-       int i;
+       unsigned int i;
+
        for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
                const char *str = attr_names[i];
                if (!strncasecmp(name, str, len) && !str[len])
@@ -222,10 +224,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
 {
        if (!*color)
                return fwrite(buf, count, 1, fp) != 1;
+
        while (count) {
                char *p = memchr(buf, '\n', count);
+
                if (p != buf && (fputs(color, fp) < 0 ||
-                               fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
+                               fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
                                fputs(PERF_COLOR_RESET, fp) < 0))
                        return -1;
                if (!p)
@@ -238,4 +242,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
        return 0;
 }
 
+char *get_percent_color(double percent)
+{
+       char *color = PERF_COLOR_NORMAL;
 
+       /*
+        * We color high-overhead entries in red, mid-overhead
+        * entries in green - and keep the low overhead places
+        * normal:
+        */
+       if (percent >= MIN_RED)
+               color = PERF_COLOR_RED;
+       else {
+               if (percent > MIN_GREEN)
+                       color = PERF_COLOR_GREEN;
+       }
+       return color;
+}
+
+int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
+{
+       int r;
+       char *color;
+
+       color = get_percent_color(percent);
+       r = color_fprintf(fp, color, fmt, percent);
+
+       return r;
+}
index 5abfd379582b40428f62807b5aefa81a239a49d2..706cec50bd25188d3f123c338e4c22436f859d80 100644 (file)
@@ -15,6 +15,9 @@
 #define PERF_COLOR_CYAN                "\033[36m"
 #define PERF_COLOR_BG_RED      "\033[41m"
 
+#define MIN_GREEN      0.5
+#define MIN_RED                5.0
+
 /*
  * This variable stores the value of color.ui
  */
@@ -32,5 +35,7 @@ void color_parse_mem(const char *value, int len, const char *var, char *dst);
 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
+int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
+char *get_percent_color(double percent);
 
 #endif /* COLOR_H */
index 3dd13faa6a27f9e1378184bd3349c2a3cf51f073..780df541006dd2dae77608ade75ad23069203d5f 100644 (file)
@@ -47,10 +47,12 @@ static int get_next_char(void)
 static char *parse_value(void)
 {
        static char value[1024];
-       int quote = 0, comment = 0, len = 0, space = 0;
+       int quote = 0, comment = 0, space = 0;
+       size_t len = 0;
 
        for (;;) {
                int c = get_next_char();
+
                if (len >= sizeof(value) - 1)
                        return NULL;
                if (c == '\n') {
@@ -353,13 +355,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
        return 0;
 }
 
-static int perf_default_core_config(const char *var, const char *value)
+static int perf_default_core_config(const char *var __used, const char *value __used)
 {
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
 
-int perf_default_config(const char *var, const char *value, void *dummy)
+int perf_default_config(const char *var, const char *value, void *dummy __used)
 {
        if (!prefixcmp(var, "core."))
                return perf_default_core_config(var, value);
@@ -471,10 +473,10 @@ static int matches(const char* key, const char* value)
                  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value, void *cb)
+static int store_aux(const char* key, const char* value, void *cb __used)
 {
+       int section_len;
        const char *ep;
-       size_t section_len;
 
        switch (store.state) {
        case KEY_SEEN:
@@ -551,7 +553,7 @@ static int store_write_section(int fd, const char* key)
                strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
        }
 
-       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
        strbuf_release(&sb);
 
        return success;
@@ -599,7 +601,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
                }
        strbuf_addf(&sb, "%s\n", quote);
 
-       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
        strbuf_release(&sb);
 
        return success;
@@ -741,7 +743,7 @@ int perf_config_set_multivar(const char* key, const char* value,
        } else {
                struct stat st;
                char* contents;
-               size_t contents_sz, copy_begin, copy_end;
+               ssize_t contents_sz, copy_begin, copy_end;
                int i, new_line = 0;
 
                if (value_regex == NULL)
index d39292263153021ac44a6f9b4e2779ce63478094..34a3528673822622019687929f0499c4ebc0de1a 100644 (file)
@@ -1,6 +1,9 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include "quote.h"
+
+#include <string.h>
+
 #define MAX_ARGS       32
 
 extern char **environ;
@@ -51,7 +54,7 @@ const char *perf_extract_argv0_path(const char *argv0)
                slash--;
 
        if (slash >= argv0) {
-               argv0_path = strndup(argv0, slash - argv0);
+               argv0_path = xstrndup(argv0, slash - argv0);
                return slash + 1;
        }
 
index b5ef53ad4c7a1e19309095a3da2d3d4238f22f91..bf280449fcfda3b84a0361548960853721a22323 100644 (file)
@@ -16,7 +16,7 @@ struct perf_header {
        int frozen;
        int attrs, size;
        struct perf_header_attr **attr;
-       off_t attr_offset;
+       s64 attr_offset;
        u64 data_offset;
        u64 data_size;
 };
index 17a00e0df2c493ee24c8bc66654d9d694281e0c3..fbb00978b2e2988045f4f970964b7c5826c1cba4 100644 (file)
@@ -26,7 +26,7 @@ static int term_columns(void)
        return 80;
 }
 
-void add_cmdname(struct cmdnames *cmds, const char *name, int len)
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
 {
        struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
 
@@ -40,7 +40,8 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 
 static void clean_cmdnames(struct cmdnames *cmds)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < cmds->cnt; ++i)
                free(cmds->names[i]);
        free(cmds->names);
@@ -57,7 +58,7 @@ static int cmdname_compare(const void *a_, const void *b_)
 
 static void uniq(struct cmdnames *cmds)
 {
-       int i, j;
+       unsigned int i, j;
 
        if (!cmds->cnt)
                return;
@@ -71,7 +72,7 @@ static void uniq(struct cmdnames *cmds)
 
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
 {
-       int ci, cj, ei;
+       size_t ci, cj, ei;
        int cmp;
 
        ci = cj = ei = 0;
@@ -106,8 +107,9 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
                printf("  ");
 
                for (j = 0; j < cols; j++) {
-                       int n = j * rows + i;
-                       int size = space;
+                       unsigned int n = j * rows + i;
+                       unsigned int size = space;
+
                        if (n >= cmds->cnt)
                                break;
                        if (j == cols-1 || n + rows >= cmds->cnt)
@@ -208,7 +210,7 @@ void load_command_list(const char *prefix,
 void list_commands(const char *title, struct cmdnames *main_cmds,
                   struct cmdnames *other_cmds)
 {
-       int i, longest = 0;
+       unsigned int i, longest = 0;
 
        for (i = 0; i < main_cmds->cnt; i++)
                if (longest < main_cmds->names[i]->len)
@@ -239,7 +241,8 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
 
 int is_in_cmdlist(struct cmdnames *c, const char *s)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < c->cnt; i++)
                if (!strcmp(s, c->names[i]->name))
                        return 1;
@@ -271,7 +274,8 @@ static int levenshtein_compare(const void *p1, const void *p2)
 
 static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
 {
-       int i;
+       unsigned int i;
+
        ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
 
        for (i = 0; i < old->cnt; i++)
@@ -283,7 +287,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
 
 const char *help_unknown_cmd(const char *cmd)
 {
-       int i, n = 0, best_similarity = 0;
+       unsigned int i, n = 0, best_similarity = 0;
        struct cmdnames main_cmds, other_cmds;
 
        memset(&main_cmds, 0, sizeof(main_cmds));
@@ -345,7 +349,7 @@ const char *help_unknown_cmd(const char *cmd)
        exit(1);
 }
 
-int cmd_version(int argc, const char **argv, const char *prefix)
+int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
 {
        printf("perf version %s\n", perf_version_string);
        return 0;
index 56bc15406ffc55115fa1c827e0d1d5a7e74c516d..7128783637b4a7be720c49a9e74ccb43cba2cac9 100644 (file)
@@ -2,8 +2,8 @@
 #define HELP_H
 
 struct cmdnames {
-       int alloc;
-       int cnt;
+       size_t alloc;
+       size_t cnt;
        struct cmdname {
                size_t len; /* also used for similarity index in help.c */
                char name[FLEX_ARRAY];
@@ -19,7 +19,7 @@ static inline void mput_char(char c, unsigned int num)
 void load_command_list(const char *prefix,
                struct cmdnames *main_cmds,
                struct cmdnames *other_cmds);
-void add_cmdname(struct cmdnames *cmds, const char *name, int len);
+void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
 /* Here we require that excludes is a sorted list. */
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 int is_in_cmdlist(struct cmdnames *c, const char *s);
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644 (file)
index 0000000..710cecc
--- /dev/null
@@ -0,0 +1 @@
+/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644 (file)
index 0000000..a6b8739
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef PERF_LINUX_KERNEL_H_
+#define PERF_LINUX_KERNEL_H_
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                     \
+       const typeof(((type *)0)->member) * __mptr = (ptr);     \
+       (type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#ifndef max
+#define max(x, y) ({                           \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       (void) (&_max1 == &_max2);              \
+       _max1 > _max2 ? _max1 : _max2; })
+#endif
+
+#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644 (file)
index 0000000..dbe4b81
--- /dev/null
@@ -0,0 +1,18 @@
+#include "../../../../include/linux/list.h"
+
+#ifndef PERF_LIST_H
+#define PERF_LIST_H
+/**
+ * list_del_range - deletes range of entries from list.
+ * @begin: first element in the range to delete from the list.
+ * @end: last element in the range to delete from the list.
+ * Note: list_empty on the range of entries does not return true after this,
+ * the entries is in an undefined state.
+ */
+static inline void list_del_range(struct list_head *begin,
+                                 struct list_head *end)
+{
+       begin->prev->next = end->next;
+       end->next->prev = begin->prev;
+}
+#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644 (file)
index 0000000..b43e2dc
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PERF_LINUX_MODULE_H
+#define PERF_LINUX_MODULE_H
+
+#define EXPORT_SYMBOL(name)
+
+#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644 (file)
index 0000000..fef6dbc
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644 (file)
index 0000000..7841e48
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PERF_LINUX_PREFETCH_H
+#define PERF_LINUX_PREFETCH_H
+
+static inline void prefetch(void *a __attribute__((unused))) { }
+
+#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644 (file)
index 0000000..7a243a1
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/list.h b/tools/perf/util/list.h
deleted file mode 100644 (file)
index e2548e8..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-#ifndef _LINUX_LIST_H
-#define _LINUX_LIST_H
-/*
-  Copyright (C) Cast of dozens, comes from the Linux kernel
-
-  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.
-*/
-
-#include <stddef.h>
-
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1 ((void *)0x00100100)
-#define LIST_POISON2 ((void *)0x00200200)
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr:       the pointer to the member.
- * @type:      the type of the container struct this is embedded in.
- * @member:    the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({                     \
-        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
-        (type *)( (char *)__mptr - offsetof(type,member) );})
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
-       struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-       struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void INIT_LIST_HEAD(struct list_head *list)
-{
-       list->next = list;
-       list->prev = list;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
-                             struct list_head *prev,
-                             struct list_head *next)
-{
-       next->prev = new;
-       new->next = next;
-       new->prev = prev;
-       prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
-{
-       next->prev = prev;
-       prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-       entry->next = LIST_POISON1;
-       entry->prev = LIST_POISON2;
-}
-
-/**
- * list_del_range - deletes range of entries from list.
- * @beging: first element in the range to delete from the list.
- * @beging: first element in the range to delete from the list.
- * Note: list_empty on the range of entries does not return true after this,
- * the entries is in an undefined state.
- */
-static inline void list_del_range(struct list_head *begin,
-                                 struct list_head *end)
-{
-       begin->prev->next = end->next;
-       end->next->prev = begin->prev;
-}
-
-/**
- * list_replace - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- * Note: if 'old' was empty, it will be overwritten.
- */
-static inline void list_replace(struct list_head *old,
-                               struct list_head *new)
-{
-       new->next = old->next;
-       new->next->prev = new;
-       new->prev = old->prev;
-       new->prev->next = new;
-}
-
-static inline void list_replace_init(struct list_head *old,
-                                       struct list_head *new)
-{
-       list_replace(old, new);
-       INIT_LIST_HEAD(old);
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-       INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
-                                 struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add_tail(list, head);
-}
-
-/**
- * list_is_last - tests whether @list is the last entry in list @head
- * @list: the entry to test
- * @head: the head of the list
- */
-static inline int list_is_last(const struct list_head *list,
-                               const struct list_head *head)
-{
-       return list->next == head;
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
-       return head->next == head;
-}
-
-/**
- * list_empty_careful - tests whether a list is empty and not being modified
- * @head: the list to test
- *
- * Description:
- * tests whether a list is empty _and_ checks that no other CPU might be
- * in the process of modifying either member (next or prev)
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- */
-static inline int list_empty_careful(const struct list_head *head)
-{
-       struct list_head *next = head->next;
-       return (next == head) && (next == head->prev);
-}
-
-static inline void __list_splice(struct list_head *list,
-                                struct list_head *head)
-{
-       struct list_head *first = list->next;
-       struct list_head *last = list->prev;
-       struct list_head *at = head->next;
-
-       first->prev = head;
-       head->next = first;
-
-       last->next = at;
-       at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(struct list_head *list, struct list_head *head)
-{
-       if (!list_empty(list))
-               __list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
-                                   struct list_head *head)
-{
-       if (!list_empty(list)) {
-               __list_splice(list, head);
-               INIT_LIST_HEAD(list);
-       }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
-       container_of(ptr, type, member)
-
-/**
- * list_first_entry - get the first element from a list
- * @ptr:       the list head to take the element from.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_first_entry(ptr, type, member) \
-       list_entry((ptr)->next, type, member)
-
-/**
- * list_for_each       -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- */
-#define list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); \
-               pos = pos->next)
-
-/**
- * __list_for_each     -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_prev  -       iterate over a list backwards
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- */
-#define list_for_each_prev(pos, head) \
-       for (pos = (head)->prev; pos != (head); \
-               pos = pos->prev)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:       the &struct list_head to use as a loop cursor.
- * @n:         another &struct list_head to use as temporary storage
- * @head:      the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
-       for (pos = (head)->next, n = pos->next; pos != (head); \
-               pos = n, n = pos->next)
-
-/**
- * list_for_each_entry -       iterate over list of given type
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member)                         \
-       for (pos = list_entry((head)->next, typeof(*pos), member);      \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member)                 \
-       for (pos = list_entry((head)->prev, typeof(*pos), member);      \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.prev, typeof(*pos), member))
-
-/**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
- * @pos:       the type * to use as a start point
- * @head:      the head of the list
- * @member:    the name of the list_struct within the struct.
- *
- * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
- */
-#define list_prepare_entry(pos, head, member) \
-       ((pos) ? : list_entry(head, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue - continue iteration over list of given type
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Continue to iterate over list of given type, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue(pos, head, member)                \
-       for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_from - iterate over list of given type from the current point
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing from current position.
- */
-#define list_for_each_entry_from(pos, head, member)                    \
-       for (; &pos->member != (head);  \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member)                 \
-       for (pos = list_entry((head)->next, typeof(*pos), member),      \
-               n = list_entry(pos->member.next, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_continue
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
- */
-#define list_for_each_entry_safe_continue(pos, n, head, member)                \
-       for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
-               n = list_entry(pos->member.next, typeof(*pos), member);         \
-            &pos->member != (head);                                            \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_from
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
- */
-#define list_for_each_entry_safe_from(pos, n, head, member)                    \
-       for (n = list_entry(pos->member.next, typeof(*pos), member);            \
-            &pos->member != (head);                                            \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_reverse
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_struct within the struct.
- *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
- */
-#define list_for_each_entry_safe_reverse(pos, n, head, member)         \
-       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
-               n = list_entry(pos->member.prev, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.prev, typeof(*n), member))
-
-/*
- * Double linked lists with a single pointer list head.
- * Mostly useful for hash tables where the two pointer list head is
- * too wasteful.
- * You lose the ability to access the tail in O(1).
- */
-
-struct hlist_head {
-       struct hlist_node *first;
-};
-
-struct hlist_node {
-       struct hlist_node *next, **pprev;
-};
-
-#define HLIST_HEAD_INIT { .first = NULL }
-#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
-#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-static inline void INIT_HLIST_NODE(struct hlist_node *h)
-{
-       h->next = NULL;
-       h->pprev = NULL;
-}
-
-static inline int hlist_unhashed(const struct hlist_node *h)
-{
-       return !h->pprev;
-}
-
-static inline int hlist_empty(const struct hlist_head *h)
-{
-       return !h->first;
-}
-
-static inline void __hlist_del(struct hlist_node *n)
-{
-       struct hlist_node *next = n->next;
-       struct hlist_node **pprev = n->pprev;
-       *pprev = next;
-       if (next)
-               next->pprev = pprev;
-}
-
-static inline void hlist_del(struct hlist_node *n)
-{
-       __hlist_del(n);
-       n->next = LIST_POISON1;
-       n->pprev = LIST_POISON2;
-}
-
-static inline void hlist_del_init(struct hlist_node *n)
-{
-       if (!hlist_unhashed(n)) {
-               __hlist_del(n);
-               INIT_HLIST_NODE(n);
-       }
-}
-
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
-       struct hlist_node *first = h->first;
-       n->next = first;
-       if (first)
-               first->pprev = &n->next;
-       h->first = n;
-       n->pprev = &h->first;
-}
-
-/* next must be != NULL */
-static inline void hlist_add_before(struct hlist_node *n,
-                                       struct hlist_node *next)
-{
-       n->pprev = next->pprev;
-       n->next = next;
-       next->pprev = &n->next;
-       *(n->pprev) = n;
-}
-
-static inline void hlist_add_after(struct hlist_node *n,
-                                       struct hlist_node *next)
-{
-       next->next = n->next;
-       n->next = next;
-       next->pprev = &n->next;
-
-       if(next->next)
-               next->next->pprev  = &next->next;
-}
-
-#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
-
-#define hlist_for_each(pos, head) \
-       for (pos = (head)->first; pos; \
-            pos = pos->next)
-
-#define hlist_for_each_safe(pos, n, head) \
-       for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
-            pos = n)
-
-/**
- * hlist_for_each_entry        - iterate over list of given type
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry(tpos, pos, head, member)                   \
-       for (pos = (head)->first;                                        \
-            pos &&                      \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_continue(tpos, pos, member)                \
-       for (pos = (pos)->next;                                          \
-            pos &&                      \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_from(tpos, pos, member)                    \
-       for (; pos &&                    \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = pos->next)
-
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct hlist_node to use as a loop cursor.
- * @n:         another &struct hlist_node to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_safe(tpos, pos, n, head, member)           \
-       for (pos = (head)->first;                                        \
-            pos && ({ n = pos->next; 1; }) &&                           \
-               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
-            pos = n)
-
-#endif
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644 (file)
index 0000000..ddabe92
--- /dev/null
@@ -0,0 +1,509 @@
+#include "util.h"
+#include "../perf.h"
+#include "string.h"
+#include "module.h"
+
+#include <libelf.h>
+#include <gelf.h>
+#include <elf.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+static unsigned int crc32(const char *p, unsigned int len)
+{
+       int i;
+       unsigned int crc = 0;
+
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+       }
+       return crc;
+}
+
+/* module section methods */
+
+struct sec_dso *sec_dso__new_dso(const char *name)
+{
+       struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
+
+       if (self != NULL) {
+               strcpy(self->name, name);
+               self->secs = RB_ROOT;
+               self->find_section = sec_dso__find_section;
+       }
+
+       return self;
+}
+
+static void sec_dso__delete_section(struct section *self)
+{
+       free(((void *)self));
+}
+
+void sec_dso__delete_sections(struct sec_dso *self)
+{
+       struct section *pos;
+       struct rb_node *next = rb_first(&self->secs);
+
+       while (next) {
+               pos = rb_entry(next, struct section, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, &self->secs);
+               sec_dso__delete_section(pos);
+       }
+}
+
+void sec_dso__delete_self(struct sec_dso *self)
+{
+       sec_dso__delete_sections(self);
+       free(self);
+}
+
+static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
+{
+       struct rb_node **p = &self->secs.rb_node;
+       struct rb_node *parent = NULL;
+       const u64 hash = sec->hash;
+       struct section *s;
+
+       while (*p != NULL) {
+               parent = *p;
+               s = rb_entry(parent, struct section, rb_node);
+               if (hash < s->hash)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&sec->rb_node, parent, p);
+       rb_insert_color(&sec->rb_node, &self->secs);
+}
+
+struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
+{
+       struct rb_node *n;
+       u64 hash;
+       int len;
+
+       if (self == NULL)
+               return NULL;
+
+       len = strlen(name);
+       hash = crc32(name, len);
+
+       n = self->secs.rb_node;
+
+       while (n) {
+               struct section *s = rb_entry(n, struct section, rb_node);
+
+               if (hash < s->hash)
+                       n = n->rb_left;
+               else if (hash > s->hash)
+                       n = n->rb_right;
+               else {
+                       if (!strcmp(name, s->name))
+                               return s;
+                       else
+                               n = rb_next(&s->rb_node);
+               }
+       }
+
+       return NULL;
+}
+
+static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
+{
+       return fprintf(fp, "name:%s vma:%llx path:%s\n",
+                      self->name, self->vma, self->path);
+}
+
+size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
+{
+       size_t ret = fprintf(fp, "dso: %s\n", self->name);
+
+       struct rb_node *nd;
+       for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
+               struct section *pos = rb_entry(nd, struct section, rb_node);
+               ret += sec_dso__fprintf_section(pos, fp);
+       }
+
+       return ret;
+}
+
+static struct section *section__new(const char *name, const char *path)
+{
+       struct section *self = calloc(1, sizeof(*self));
+
+       if (!self)
+               goto out_failure;
+
+       self->name = calloc(1, strlen(name) + 1);
+       if (!self->name)
+               goto out_failure;
+
+       self->path = calloc(1, strlen(path) + 1);
+       if (!self->path)
+               goto out_failure;
+
+       strcpy(self->name, name);
+       strcpy(self->path, path);
+       self->hash = crc32(self->name, strlen(name));
+
+       return self;
+
+out_failure:
+       if (self) {
+               if (self->name)
+                       free(self->name);
+               if (self->path)
+                       free(self->path);
+               free(self);
+       }
+
+       return NULL;
+}
+
+/* module methods */
+
+struct mod_dso *mod_dso__new_dso(const char *name)
+{
+       struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
+
+       if (self != NULL) {
+               strcpy(self->name, name);
+               self->mods = RB_ROOT;
+               self->find_module = mod_dso__find_module;
+       }
+
+       return self;
+}
+
+static void mod_dso__delete_module(struct module *self)
+{
+       free(((void *)self));
+}
+
+void mod_dso__delete_modules(struct mod_dso *self)
+{
+       struct module *pos;
+       struct rb_node *next = rb_first(&self->mods);
+
+       while (next) {
+               pos = rb_entry(next, struct module, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, &self->mods);
+               mod_dso__delete_module(pos);
+       }
+}
+
+void mod_dso__delete_self(struct mod_dso *self)
+{
+       mod_dso__delete_modules(self);
+       free(self);
+}
+
+static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
+{
+       struct rb_node **p = &self->mods.rb_node;
+       struct rb_node *parent = NULL;
+       const u64 hash = mod->hash;
+       struct module *m;
+
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct module, rb_node);
+               if (hash < m->hash)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&mod->rb_node, parent, p);
+       rb_insert_color(&mod->rb_node, &self->mods);
+}
+
+struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
+{
+       struct rb_node *n;
+       u64 hash;
+       int len;
+
+       if (self == NULL)
+               return NULL;
+
+       len = strlen(name);
+       hash = crc32(name, len);
+
+       n = self->mods.rb_node;
+
+       while (n) {
+               struct module *m = rb_entry(n, struct module, rb_node);
+
+               if (hash < m->hash)
+                       n = n->rb_left;
+               else if (hash > m->hash)
+                       n = n->rb_right;
+               else {
+                       if (!strcmp(name, m->name))
+                               return m;
+                       else
+                               n = rb_next(&m->rb_node);
+               }
+       }
+
+       return NULL;
+}
+
+static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
+{
+       return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
+}
+
+size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
+{
+       struct rb_node *nd;
+       size_t ret;
+
+       ret = fprintf(fp, "dso: %s\n", self->name);
+
+       for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
+               struct module *pos = rb_entry(nd, struct module, rb_node);
+
+               ret += mod_dso__fprintf_module(pos, fp);
+       }
+
+       return ret;
+}
+
+static struct module *module__new(const char *name, const char *path)
+{
+       struct module *self = calloc(1, sizeof(*self));
+
+       if (!self)
+               goto out_failure;
+
+       self->name = calloc(1, strlen(name) + 1);
+       if (!self->name)
+               goto out_failure;
+
+       self->path = calloc(1, strlen(path) + 1);
+       if (!self->path)
+               goto out_failure;
+
+       strcpy(self->name, name);
+       strcpy(self->path, path);
+       self->hash = crc32(self->name, strlen(name));
+
+       return self;
+
+out_failure:
+       if (self) {
+               if (self->name)
+                       free(self->name);
+               if (self->path)
+                       free(self->path);
+               free(self);
+       }
+
+       return NULL;
+}
+
+static int mod_dso__load_sections(struct module *mod)
+{
+       int count = 0, path_len;
+       struct dirent *entry;
+       char *line = NULL;
+       char *dir_path;
+       DIR *dir;
+       size_t n;
+
+       path_len = strlen("/sys/module/");
+       path_len += strlen(mod->name);
+       path_len += strlen("/sections/");
+
+       dir_path = calloc(1, path_len + 1);
+       if (dir_path == NULL)
+               goto out_failure;
+
+       strcat(dir_path, "/sys/module/");
+       strcat(dir_path, mod->name);
+       strcat(dir_path, "/sections/");
+
+       dir = opendir(dir_path);
+       if (dir == NULL)
+               goto out_free;
+
+       while ((entry = readdir(dir))) {
+               struct section *section;
+               char *path, *vma;
+               int line_len;
+               FILE *file;
+
+               if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
+                       continue;
+
+               path = calloc(1, path_len + strlen(entry->d_name) + 1);
+               if (path == NULL)
+                       break;
+               strcat(path, dir_path);
+               strcat(path, entry->d_name);
+
+               file = fopen(path, "r");
+               if (file == NULL) {
+                       free(path);
+                       break;
+               }
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               if (!line) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               line[--line_len] = '\0'; /* \n */
+
+               vma = strstr(line, "0x");
+               if (!vma) {
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+               vma += 2;
+
+               section = section__new(entry->d_name, path);
+               if (!section) {
+                       fprintf(stderr, "load_sections: allocation error\n");
+                       free(path);
+                       fclose(file);
+                       break;
+               }
+
+               hex2u64(vma, &section->vma);
+               sec_dso__insert_section(mod->sections, section);
+
+               free(path);
+               fclose(file);
+               count++;
+       }
+
+       closedir(dir);
+       free(line);
+       free(dir_path);
+
+       return count;
+
+out_free:
+       free(dir_path);
+
+out_failure:
+       return count;
+}
+
+static int mod_dso__load_module_paths(struct mod_dso *self)
+{
+       struct utsname uts;
+       int count = 0, len;
+       char *line = NULL;
+       FILE *file;
+       char *path;
+       size_t n;
+
+       if (uname(&uts) < 0)
+               goto out_failure;
+
+       len = strlen("/lib/modules/");
+       len += strlen(uts.release);
+       len += strlen("/modules.dep");
+
+       path = calloc(1, len);
+       if (path == NULL)
+               goto out_failure;
+
+       strcat(path, "/lib/modules/");
+       strcat(path, uts.release);
+       strcat(path, "/modules.dep");
+
+       file = fopen(path, "r");
+       free(path);
+       if (file == NULL)
+               goto out_failure;
+
+       while (!feof(file)) {
+               char *path, *name, *tmp;
+               struct module *module;
+               int line_len, len;
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
+
+               if (!line)
+                       goto out_failure;
+
+               line[--line_len] = '\0'; /* \n */
+
+               path = strtok(line, ":");
+               if (!path)
+                       goto out_failure;
+
+               name = strdup(path);
+               name = strtok(name, "/");
+
+               tmp = name;
+
+               while (tmp) {
+                       tmp = strtok(NULL, "/");
+                       if (tmp)
+                               name = tmp;
+               }
+               name = strsep(&name, ".");
+
+               /* Quirk: replace '-' with '_' in sound modules */
+               for (len = strlen(name); len; len--) {
+                       if (*(name+len) == '-')
+                               *(name+len) = '_';
+               }
+
+               module = module__new(name, path);
+               if (!module) {
+                       fprintf(stderr, "load_module_paths: allocation error\n");
+                       goto out_failure;
+               }
+               mod_dso__insert_module(self, module);
+
+               module->sections = sec_dso__new_dso("sections");
+               if (!module->sections) {
+                       fprintf(stderr, "load_module_paths: allocation error\n");
+                       goto out_failure;
+               }
+
+               module->active = mod_dso__load_sections(module);
+
+               if (module->active > 0)
+                       count++;
+       }
+
+       free(line);
+       fclose(file);
+
+       return count;
+
+out_failure:
+       return -1;
+}
+
+int mod_dso__load_modules(struct mod_dso *dso)
+{
+       int err;
+
+       err = mod_dso__load_module_paths(dso);
+
+       return err;
+}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644 (file)
index 0000000..8a592ef
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _PERF_MODULE_
+#define _PERF_MODULE_ 1
+
+#include <linux/types.h>
+#include "../types.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+
+struct section {
+       struct rb_node  rb_node;
+       u64             hash;
+       u64             vma;
+       char            *name;
+       char            *path;
+};
+
+struct sec_dso {
+       struct list_head node;
+       struct rb_root   secs;
+       struct section    *(*find_section)(struct sec_dso *, const char *name);
+       char             name[0];
+};
+
+struct module {
+       struct rb_node  rb_node;
+       u64             hash;
+       char            *name;
+       char            *path;
+       struct sec_dso  *sections;
+       int             active;
+};
+
+struct mod_dso {
+       struct list_head node;
+       struct rb_root   mods;
+       struct module    *(*find_module)(struct mod_dso *, const char *name);
+       char             name[0];
+};
+
+struct sec_dso *sec_dso__new_dso(const char *name);
+void sec_dso__delete_sections(struct sec_dso *self);
+void sec_dso__delete_self(struct sec_dso *self);
+size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
+struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
+
+struct mod_dso *mod_dso__new_dso(const char *name);
+void mod_dso__delete_modules(struct mod_dso *self);
+void mod_dso__delete_self(struct mod_dso *self);
+size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
+struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
+int mod_dso__load_modules(struct mod_dso *dso);
+
+#endif /* _PERF_MODULE_ */
index 4d042f104cdcf44539478f66f43e1cf5ea54520a..7bdad8df22a66b5ea10e85cdbe9b5bea806f4bb4 100644 (file)
@@ -5,6 +5,7 @@
 #include "parse-events.h"
 #include "exec_cmd.h"
 #include "string.h"
+#include "cache.h"
 
 extern char *strcasestr(const char *haystack, const char *needle);
 
@@ -19,6 +20,8 @@ struct event_symbol {
        char    *alias;
 };
 
+char debugfs_path[MAXPATHLEN];
+
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
 
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
 #define MAX_ALIASES 8
 
 static char *hw_cache[][MAX_ALIASES] = {
- { "L1-d$",    "l1-d",         "l1d",          "L1-data",              },
- { "L1-i$",    "l1-i",         "l1i",          "L1-instruction",       },
+ { "L1-dcache",        "l1-d",         "l1d",          "L1-data",              },
+ { "L1-icache",        "l1-i",         "l1i",          "L1-instruction",       },
  { "LLC",      "L2"                                                    },
  { "dTLB",     "d-tlb",        "Data-TLB",                             },
  { "iTLB",     "i-tlb",        "Instruction-TLB",                      },
@@ -110,6 +113,88 @@ static unsigned long hw_cache_stat[C(MAX)] = {
  [C(BPU)]      = (CACHE_READ),
 };
 
+#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st)           \
+       while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next)        \
+       if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path,                  \
+                       sys_dirent.d_name) &&                                  \
+          (!stat(file, &st)) && (S_ISDIR(st.st_mode)) &&                      \
+          (strcmp(sys_dirent.d_name, ".")) &&                                 \
+          (strcmp(sys_dirent.d_name, "..")))
+
+#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st)    \
+       while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next)        \
+       if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path,               \
+                    sys_dirent.d_name, evt_dirent.d_name) &&                  \
+          (!stat(file, &st)) && (S_ISDIR(st.st_mode)) &&                      \
+          (strcmp(evt_dirent.d_name, ".")) &&                                 \
+          (strcmp(evt_dirent.d_name, "..")))
+
+#define MAX_EVENT_LENGTH 30
+
+int valid_debugfs_mount(const char *debugfs)
+{
+       struct statfs st_fs;
+
+       if (statfs(debugfs, &st_fs) < 0)
+               return -ENOENT;
+       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+               return -ENOENT;
+       return 0;
+}
+
+static char *tracepoint_id_to_name(u64 config)
+{
+       static char tracepoint_name[2 * MAX_EVENT_LENGTH];
+       DIR *sys_dir, *evt_dir;
+       struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
+       struct stat st;
+       char id_buf[4];
+       int fd;
+       u64 id;
+       char evt_path[MAXPATHLEN];
+
+       if (valid_debugfs_mount(debugfs_path))
+               return "unkown";
+
+       sys_dir = opendir(debugfs_path);
+       if (!sys_dir)
+               goto cleanup;
+
+       for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
+               evt_dir = opendir(evt_path);
+               if (!evt_dir)
+                       goto cleanup;
+               for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
+                                                               evt_path, st) {
+                       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
+                                debugfs_path, sys_dirent.d_name,
+                                evt_dirent.d_name);
+                       fd = open(evt_path, O_RDONLY);
+                       if (fd < 0)
+                               continue;
+                       if (read(fd, id_buf, sizeof(id_buf)) < 0) {
+                               close(fd);
+                               continue;
+                       }
+                       close(fd);
+                       id = atoll(id_buf);
+                       if (id == config) {
+                               closedir(evt_dir);
+                               closedir(sys_dir);
+                               snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
+                                       "%s:%s", sys_dirent.d_name,
+                                       evt_dirent.d_name);
+                               return tracepoint_name;
+                       }
+               }
+               closedir(evt_dir);
+       }
+
+cleanup:
+       closedir(sys_dir);
+       return "unkown";
+}
+
 static int is_cache_op_valid(u8 cache_type, u8 cache_op)
 {
        if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -177,6 +262,9 @@ char *event_name(int counter)
                        return sw_event_names[config];
                return "unknown-software";
 
+       case PERF_TYPE_TRACEPOINT:
+               return tracepoint_id_to_name(config);
+
        default:
                break;
        }
@@ -184,16 +272,20 @@ char *event_name(int counter)
        return "unknown";
 }
 
-static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
+static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
 {
        int i, j;
+       int n, longest = -1;
 
        for (i = 0; i < size; i++) {
-               for (j = 0; j < MAX_ALIASES; j++) {
-                       if (!names[i][j])
-                               break;
-                       if (strcasestr(str, names[i][j]))
-                               return i;
+               for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+                       n = strlen(names[i][j]);
+                       if (n > longest && !strncasecmp(*str, names[i][j], n))
+                               longest = n;
+               }
+               if (longest > 0) {
+                       *str += longest;
+                       return i;
                }
        }
 
@@ -201,30 +293,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
 }
 
 static int
-parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
+parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
 {
-       int cache_type = -1, cache_op = 0, cache_result = 0;
+       const char *s = *str;
+       int cache_type = -1, cache_op = -1, cache_result = -1;
 
-       cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
+       cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
        /*
         * No fallback - if we cannot get a clear cache type
         * then bail out:
         */
        if (cache_type == -1)
-               return -EINVAL;
+               return 0;
+
+       while ((cache_op == -1 || cache_result == -1) && *s == '-') {
+               ++s;
+
+               if (cache_op == -1) {
+                       cache_op = parse_aliases(&s, hw_cache_op,
+                                               PERF_COUNT_HW_CACHE_OP_MAX);
+                       if (cache_op >= 0) {
+                               if (!is_cache_op_valid(cache_type, cache_op))
+                                       return 0;
+                               continue;
+                       }
+               }
+
+               if (cache_result == -1) {
+                       cache_result = parse_aliases(&s, hw_cache_result,
+                                               PERF_COUNT_HW_CACHE_RESULT_MAX);
+                       if (cache_result >= 0)
+                               continue;
+               }
+
+               /*
+                * Can't parse this as a cache op or result, so back up
+                * to the '-'.
+                */
+               --s;
+               break;
+       }
 
-       cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
        /*
         * Fall back to reads:
         */
        if (cache_op == -1)
                cache_op = PERF_COUNT_HW_CACHE_OP_READ;
 
-       if (!is_cache_op_valid(cache_type, cache_op))
-               return -EINVAL;
-
-       cache_result = parse_aliases(str, hw_cache_result,
-                                       PERF_COUNT_HW_CACHE_RESULT_MAX);
        /*
         * Fall back to accesses:
         */
@@ -234,93 +349,202 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
        attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
        attr->type = PERF_TYPE_HW_CACHE;
 
-       return 0;
+       *str = s;
+       return 1;
+}
+
+static int parse_tracepoint_event(const char **strp,
+                                   struct perf_counter_attr *attr)
+{
+       const char *evt_name;
+       char sys_name[MAX_EVENT_LENGTH];
+       char id_buf[4];
+       int fd;
+       unsigned int sys_length, evt_length;
+       u64 id;
+       char evt_path[MAXPATHLEN];
+
+       if (valid_debugfs_mount(debugfs_path))
+               return 0;
+
+       evt_name = strchr(*strp, ':');
+       if (!evt_name)
+               return 0;
+
+       sys_length = evt_name - *strp;
+       if (sys_length >= MAX_EVENT_LENGTH)
+               return 0;
+
+       strncpy(sys_name, *strp, sys_length);
+       sys_name[sys_length] = '\0';
+       evt_name = evt_name + 1;
+       evt_length = strlen(evt_name);
+       if (evt_length >= MAX_EVENT_LENGTH)
+               return 0;
+
+       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+                sys_name, evt_name);
+       fd = open(evt_path, O_RDONLY);
+       if (fd < 0)
+               return 0;
+
+       if (read(fd, id_buf, sizeof(id_buf)) < 0) {
+               close(fd);
+               return 0;
+       }
+       close(fd);
+       id = atoll(id_buf);
+       attr->config = id;
+       attr->type = PERF_TYPE_TRACEPOINT;
+       *strp = evt_name + evt_length;
+       return 1;
 }
 
 static int check_events(const char *str, unsigned int i)
 {
-       if (!strncmp(str, event_symbols[i].symbol,
-                    strlen(event_symbols[i].symbol)))
-               return 1;
+       int n;
 
-       if (strlen(event_symbols[i].alias))
-               if (!strncmp(str, event_symbols[i].alias,
-                            strlen(event_symbols[i].alias)))
-                       return 1;
+       n = strlen(event_symbols[i].symbol);
+       if (!strncmp(str, event_symbols[i].symbol, n))
+               return n;
+
+       n = strlen(event_symbols[i].alias);
+       if (n)
+               if (!strncmp(str, event_symbols[i].alias, n))
+                       return n;
        return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
+static int
+parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
 {
-       u64 config, id;
-       int type;
+       const char *str = *strp;
        unsigned int i;
-       const char *sep, *pstr;
+       int n;
 
-       if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
-               attr->type = PERF_TYPE_RAW;
-               attr->config = config;
+       for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+               n = check_events(str, i);
+               if (n > 0) {
+                       attr->type = event_symbols[i].type;
+                       attr->config = event_symbols[i].config;
+                       *strp = str + n;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       u64 config;
+       int n;
 
+       if (*str != 'r')
                return 0;
+       n = hex2u64(str + 1, &config);
+       if (n > 0) {
+               *strp = str + n + 1;
+               attr->type = PERF_TYPE_RAW;
+               attr->config = config;
+               return 1;
        }
+       return 0;
+}
 
-       pstr = str;
-       sep = strchr(pstr, ':');
-       if (sep) {
-               type = atoi(pstr);
-               pstr = sep + 1;
-               id = atoi(pstr);
-               sep = strchr(pstr, ':');
-               if (sep) {
-                       pstr = sep + 1;
-                       if (strchr(pstr, 'k'))
-                               attr->exclude_user = 1;
-                       if (strchr(pstr, 'u'))
-                               attr->exclude_kernel = 1;
+static int
+parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       char *endp;
+       unsigned long type;
+       u64 config;
+
+       type = strtoul(str, &endp, 0);
+       if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
+               str = endp + 1;
+               config = strtoul(str, &endp, 0);
+               if (endp > str) {
+                       attr->type = type;
+                       attr->config = config;
+                       *strp = endp;
+                       return 1;
                }
-               attr->type = type;
-               attr->config = id;
+       }
+       return 0;
+}
 
+static int
+parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
+{
+       const char *str = *strp;
+       int eu = 1, ek = 1, eh = 1;
+
+       if (*str++ != ':')
                return 0;
+       while (*str) {
+               if (*str == 'u')
+                       eu = 0;
+               else if (*str == 'k')
+                       ek = 0;
+               else if (*str == 'h')
+                       eh = 0;
+               else
+                       break;
+               ++str;
+       }
+       if (str >= *strp + 2) {
+               *strp = str;
+               attr->exclude_user   = eu;
+               attr->exclude_kernel = ek;
+               attr->exclude_hv     = eh;
+               return 1;
        }
+       return 0;
+}
 
-       for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-               if (check_events(str, i)) {
-                       attr->type = event_symbols[i].type;
-                       attr->config = event_symbols[i].config;
+/*
+ * Each event can have multiple symbolic names.
+ * Symbolic names are (almost) exactly matched.
+ */
+static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
+{
+       if (!(parse_tracepoint_event(str, attr) ||
+             parse_raw_event(str, attr) ||
+             parse_numeric_event(str, attr) ||
+             parse_symbolic_event(str, attr) ||
+             parse_generic_hw_event(str, attr)))
+               return 0;
 
-                       return 0;
-               }
-       }
+       parse_event_modifier(str, attr);
 
-       return parse_generic_hw_symbols(str, attr);
+       return 1;
 }
 
-int parse_events(const struct option *opt, const char *str, int unset)
+int parse_events(const struct option *opt __used, const char *str, int unset __used)
 {
        struct perf_counter_attr attr;
-       int ret;
 
-       memset(&attr, 0, sizeof(attr));
-again:
-       if (nr_counters == MAX_COUNTERS)
-               return -1;
+       for (;;) {
+               if (nr_counters == MAX_COUNTERS)
+                       return -1;
+
+               memset(&attr, 0, sizeof(attr));
+               if (!parse_event_symbols(&str, &attr))
+                       return -1;
 
-       ret = parse_event_symbols(str, &attr);
-       if (ret < 0)
-               return ret;
+               if (!(*str == 0 || *str == ',' || isspace(*str)))
+                       return -1;
 
-       attrs[nr_counters] = attr;
-       nr_counters++;
+               attrs[nr_counters] = attr;
+               nr_counters++;
 
-       str = strstr(str, ",");
-       if (str) {
-               str++;
-               goto again;
+               if (*str == 0)
+                       break;
+               if (*str == ',')
+                       ++str;
+               while (isspace(*str))
+                       ++str;
        }
 
        return 0;
@@ -334,13 +558,49 @@ static const char * const event_type_descriptors[] = {
        "Hardware cache event",
 };
 
+/*
+ * Print the events from <debugfs_mount_point>/tracing/events
+ */
+
+static void print_tracepoint_events(void)
+{
+       DIR *sys_dir, *evt_dir;
+       struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
+       struct stat st;
+       char evt_path[MAXPATHLEN];
+
+       if (valid_debugfs_mount(debugfs_path))
+               return;
+
+       sys_dir = opendir(debugfs_path);
+       if (!sys_dir)
+               goto cleanup;
+
+       for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
+               evt_dir = opendir(evt_path);
+               if (!evt_dir)
+                       goto cleanup;
+               for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
+                                                               evt_path, st) {
+                       snprintf(evt_path, MAXPATHLEN, "%s:%s",
+                                sys_dirent.d_name, evt_dirent.d_name);
+                       fprintf(stderr, "  %-40s [%s]\n", evt_path,
+                               event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
+               }
+               closedir(evt_dir);
+       }
+
+cleanup:
+       closedir(sys_dir);
+}
+
 /*
  * Print the help text for the event symbols:
  */
 void print_events(void)
 {
        struct event_symbol *syms = event_symbols;
-       unsigned int i, type, prev_type = -1;
+       unsigned int i, type, op, prev_type = -1;
        char name[40];
 
        fprintf(stderr, "\n");
@@ -348,7 +608,7 @@ void print_events(void)
 
        for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
                type = syms->type + 1;
-               if (type > ARRAY_SIZE(event_type_descriptors))
+               if (type >= ARRAY_SIZE(event_type_descriptors))
                        type = 0;
 
                if (type != prev_type)
@@ -364,10 +624,27 @@ void print_events(void)
                prev_type = type;
        }
 
+       fprintf(stderr, "\n");
+       for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+               for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+                       /* skip invalid cache type */
+                       if (!is_cache_op_valid(type, op))
+                               continue;
+
+                       for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+                               fprintf(stderr, "  %-40s [%s]\n",
+                                       event_cache_name(type, op, i),
+                                       event_type_descriptors[4]);
+                       }
+               }
+       }
+
        fprintf(stderr, "\n");
        fprintf(stderr, "  %-40s [raw hardware event descriptor]\n",
                "rNNN");
        fprintf(stderr, "\n");
 
+       print_tracepoint_events();
+
        exit(129);
 }
index e3d552908e60015517316d2d91cba6324c8fbc2f..1ea5d09b6eb14221db27cebdc9091f03c29bf53b 100644 (file)
@@ -3,6 +3,8 @@
  * Parse symbolic events/counts passed in as options:
  */
 
+struct option;
+
 extern int                     nr_counters;
 
 extern struct perf_counter_attr attrs[MAX_COUNTERS];
@@ -15,3 +17,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
 
 extern void print_events(void);
 
+extern char debugfs_path[];
+extern int valid_debugfs_mount(const char *debugfs);
+
index b3affb1658d2a1646aea5680a941c9701df27e1b..1bf67190c820041edb9e751c3aa56713394fcdce 100644 (file)
@@ -20,7 +20,8 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
        if (p->opt) {
                *arg = p->opt;
                p->opt = NULL;
-       } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
+       } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+                   **(p->argv + 1) == '-')) {
                *arg = (const char *)opt->defval;
        } else if (p->argc > 1) {
                p->argc--;
@@ -485,7 +486,7 @@ int parse_options_usage(const char * const *usagestr,
 }
 
 
-int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
+int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
                           int unset)
 {
        int *target = opt->value;
index a1039a6ce0ebabdc561fc1b061e3e2ead566cc83..8aa3464c709054ba8b6275f39d3bead3873f5936 100644 (file)
@@ -90,21 +90,22 @@ struct option {
        intptr_t defval;
 };
 
-#define OPT_END()                   { OPTION_END }
-#define OPT_ARGUMENT(l, h)          { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
-#define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
-#define OPT_BIT(s, l, v, h, b)      { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
-#define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
-#define OPT_SET_INT(s, l, v, h, i)  { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
-#define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
-#define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
-#define OPT_LONG(s, l, v, h)        { OPTION_LONG, (s), (l), (v), NULL, (h) }
-#define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) }
+#define OPT_END()                   { .type = OPTION_END }
+#define OPT_ARGUMENT(l, h)          { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
+#define OPT_GROUP(h)                { .type = OPTION_GROUP, .help = (h) }
+#define OPT_BIT(s, l, v, h, b)      { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) }
+#define OPT_BOOLEAN(s, l, v, h)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_SET_INT(s, l, v, h, i)  { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
+#define OPT_SET_PTR(s, l, v, h, p)  { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
+#define OPT_INTEGER(s, l, v, h)     { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
+#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
 #define OPT_DATE(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
-         parse_opt_approxidate_cb }
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
 #define OPT_CALLBACK(s, l, v, a, h, f) \
-       { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
+#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
+       { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
index f18c5212bc92b8a89437a65fbdd83c0928266110..c6e5dc0dc82f632dc2b1ae44b5f8e51f707b1755 100644 (file)
@@ -162,12 +162,16 @@ static inline int sq_must_quote(char c)
        return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
 }
 
-/* returns the longest prefix not needing a quote up to maxlen if positive.
-   This stops at the first \0 because it's marked as a character needing an
-   escape */
-static size_t next_quote_pos(const char *s, ssize_t maxlen)
+/*
+ * Returns the longest prefix not needing a quote up to maxlen if
+ * positive.
+ * This stops at the first \0 because it's marked as a character
+ * needing an escape.
+ */
+static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
 {
-       size_t len;
+       ssize_t len;
+
        if (maxlen < 0) {
                for (len = 0; !sq_must_quote(s[len]); len++);
        } else {
@@ -192,22 +196,22 @@ static size_t next_quote_pos(const char *s, ssize_t maxlen)
 static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
                                     struct strbuf *sb, FILE *fp, int no_dq)
 {
-#undef EMIT
-#define EMIT(c)                                 \
-       do {                                        \
-               if (sb) strbuf_addch(sb, (c));          \
-               if (fp) fputc((c), fp);                 \
-               count++;                                \
+#define EMIT(c)                                                        \
+       do {                                                    \
+               if (sb) strbuf_addch(sb, (c));                  \
+               if (fp) fputc((c), fp);                         \
+               count++;                                        \
        } while (0)
-#define EMITBUF(s, l)                           \
-       do {                                        \
-               int __ret;                              \
-               if (sb) strbuf_add(sb, (s), (l));       \
-               if (fp) __ret = fwrite((s), (l), 1, fp);        \
-               count += (l);                           \
+
+#define EMITBUF(s, l)                                          \
+       do {                                                    \
+               int __ret;                                      \
+               if (sb) strbuf_add(sb, (s), (l));               \
+               if (fp) __ret = fwrite((s), (l), 1, fp);        \
+               count += (l);                                   \
        } while (0)
 
-       size_t len, count = 0;
+       ssize_t len, count = 0;
        const char *p = name;
 
        for (;;) {
@@ -273,8 +277,8 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
        fputc(terminator, fp);
 }
 
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
-                                 const char *name, FILE *fp, int terminator)
+void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
+                         const char *name, FILE *fp, int terminator)
 {
        int needquote = 0;
 
@@ -306,7 +310,7 @@ char *quote_path_relative(const char *in, int len,
                len = strlen(in);
 
        /* "../" prefix itself does not need quoting, but "in" might. */
-       needquote = next_quote_pos(in, len) < len;
+       needquote = (next_quote_pos(in, len) < len);
        strbuf_setlen(out, 0);
        strbuf_grow(out, len);
 
index 5dfad89816db124e9b18abc7d2964997a55a329b..a5454a1d1c137ba3640add2945f1be186727d36c 100644 (file)
@@ -53,7 +53,7 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
 extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
 
 extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
+extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
                                  const char *name, FILE *, int terminator);
 
 /* quote path as relative to the given prefix */
diff --git a/tools/perf/util/rbtree.c b/tools/perf/util/rbtree.c
deleted file mode 100644 (file)
index b15ba9c..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea@suse.de>
-  (C) 2002  David Woodhouse <dwmw2@infradead.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, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-  linux/lib/rbtree.c
-*/
-
-#include "rbtree.h"
-
-static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *right = node->rb_right;
-       struct rb_node *parent = rb_parent(node);
-
-       if ((node->rb_right = right->rb_left))
-               rb_set_parent(right->rb_left, node);
-       right->rb_left = node;
-
-       rb_set_parent(right, parent);
-
-       if (parent)
-       {
-               if (node == parent->rb_left)
-                       parent->rb_left = right;
-               else
-                       parent->rb_right = right;
-       }
-       else
-               root->rb_node = right;
-       rb_set_parent(node, right);
-}
-
-static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *left = node->rb_left;
-       struct rb_node *parent = rb_parent(node);
-
-       if ((node->rb_left = left->rb_right))
-               rb_set_parent(left->rb_right, node);
-       left->rb_right = node;
-
-       rb_set_parent(left, parent);
-
-       if (parent)
-       {
-               if (node == parent->rb_right)
-                       parent->rb_right = left;
-               else
-                       parent->rb_left = left;
-       }
-       else
-               root->rb_node = left;
-       rb_set_parent(node, left);
-}
-
-void rb_insert_color(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *parent, *gparent;
-
-       while ((parent = rb_parent(node)) && rb_is_red(parent))
-       {
-               gparent = rb_parent(parent);
-
-               if (parent == gparent->rb_left)
-               {
-                       {
-                               register struct rb_node *uncle = gparent->rb_right;
-                               if (uncle && rb_is_red(uncle))
-                               {
-                                       rb_set_black(uncle);
-                                       rb_set_black(parent);
-                                       rb_set_red(gparent);
-                                       node = gparent;
-                                       continue;
-                               }
-                       }
-
-                       if (parent->rb_right == node)
-                       {
-                               register struct rb_node *tmp;
-                               __rb_rotate_left(parent, root);
-                               tmp = parent;
-                               parent = node;
-                               node = tmp;
-                       }
-
-                       rb_set_black(parent);
-                       rb_set_red(gparent);
-                       __rb_rotate_right(gparent, root);
-               } else {
-                       {
-                               register struct rb_node *uncle = gparent->rb_left;
-                               if (uncle && rb_is_red(uncle))
-                               {
-                                       rb_set_black(uncle);
-                                       rb_set_black(parent);
-                                       rb_set_red(gparent);
-                                       node = gparent;
-                                       continue;
-                               }
-                       }
-
-                       if (parent->rb_left == node)
-                       {
-                               register struct rb_node *tmp;
-                               __rb_rotate_right(parent, root);
-                               tmp = parent;
-                               parent = node;
-                               node = tmp;
-                       }
-
-                       rb_set_black(parent);
-                       rb_set_red(gparent);
-                       __rb_rotate_left(gparent, root);
-               }
-       }
-
-       rb_set_black(root->rb_node);
-}
-
-static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
-                            struct rb_root *root)
-{
-       struct rb_node *other;
-
-       while ((!node || rb_is_black(node)) && node != root->rb_node)
-       {
-               if (parent->rb_left == node)
-               {
-                       other = parent->rb_right;
-                       if (rb_is_red(other))
-                       {
-                               rb_set_black(other);
-                               rb_set_red(parent);
-                               __rb_rotate_left(parent, root);
-                               other = parent->rb_right;
-                       }
-                       if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-                           (!other->rb_right || rb_is_black(other->rb_right)))
-                       {
-                               rb_set_red(other);
-                               node = parent;
-                               parent = rb_parent(node);
-                       }
-                       else
-                       {
-                               if (!other->rb_right || rb_is_black(other->rb_right))
-                               {
-                                       rb_set_black(other->rb_left);
-                                       rb_set_red(other);
-                                       __rb_rotate_right(other, root);
-                                       other = parent->rb_right;
-                               }
-                               rb_set_color(other, rb_color(parent));
-                               rb_set_black(parent);
-                               rb_set_black(other->rb_right);
-                               __rb_rotate_left(parent, root);
-                               node = root->rb_node;
-                               break;
-                       }
-               }
-               else
-               {
-                       other = parent->rb_left;
-                       if (rb_is_red(other))
-                       {
-                               rb_set_black(other);
-                               rb_set_red(parent);
-                               __rb_rotate_right(parent, root);
-                               other = parent->rb_left;
-                       }
-                       if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-                           (!other->rb_right || rb_is_black(other->rb_right)))
-                       {
-                               rb_set_red(other);
-                               node = parent;
-                               parent = rb_parent(node);
-                       }
-                       else
-                       {
-                               if (!other->rb_left || rb_is_black(other->rb_left))
-                               {
-                                       rb_set_black(other->rb_right);
-                                       rb_set_red(other);
-                                       __rb_rotate_left(other, root);
-                                       other = parent->rb_left;
-                               }
-                               rb_set_color(other, rb_color(parent));
-                               rb_set_black(parent);
-                               rb_set_black(other->rb_left);
-                               __rb_rotate_right(parent, root);
-                               node = root->rb_node;
-                               break;
-                       }
-               }
-       }
-       if (node)
-               rb_set_black(node);
-}
-
-void rb_erase(struct rb_node *node, struct rb_root *root)
-{
-       struct rb_node *child, *parent;
-       int color;
-
-       if (!node->rb_left)
-               child = node->rb_right;
-       else if (!node->rb_right)
-               child = node->rb_left;
-       else
-       {
-               struct rb_node *old = node, *left;
-
-               node = node->rb_right;
-               while ((left = node->rb_left) != NULL)
-                       node = left;
-               child = node->rb_right;
-               parent = rb_parent(node);
-               color = rb_color(node);
-
-               if (child)
-                       rb_set_parent(child, parent);
-               if (parent == old) {
-                       parent->rb_right = child;
-                       parent = node;
-               } else
-                       parent->rb_left = child;
-
-               node->rb_parent_color = old->rb_parent_color;
-               node->rb_right = old->rb_right;
-               node->rb_left = old->rb_left;
-
-               if (rb_parent(old))
-               {
-                       if (rb_parent(old)->rb_left == old)
-                               rb_parent(old)->rb_left = node;
-                       else
-                               rb_parent(old)->rb_right = node;
-               } else
-                       root->rb_node = node;
-
-               rb_set_parent(old->rb_left, node);
-               if (old->rb_right)
-                       rb_set_parent(old->rb_right, node);
-               goto color;
-       }
-
-       parent = rb_parent(node);
-       color = rb_color(node);
-
-       if (child)
-               rb_set_parent(child, parent);
-       if (parent)
-       {
-               if (parent->rb_left == node)
-                       parent->rb_left = child;
-               else
-                       parent->rb_right = child;
-       }
-       else
-               root->rb_node = child;
-
- color:
-       if (color == RB_BLACK)
-               __rb_erase_color(child, parent, root);
-}
-
-/*
- * This function returns the first node (in sort order) of the tree.
- */
-struct rb_node *rb_first(const struct rb_root *root)
-{
-       struct rb_node  *n;
-
-       n = root->rb_node;
-       if (!n)
-               return NULL;
-       while (n->rb_left)
-               n = n->rb_left;
-       return n;
-}
-
-struct rb_node *rb_last(const struct rb_root *root)
-{
-       struct rb_node  *n;
-
-       n = root->rb_node;
-       if (!n)
-               return NULL;
-       while (n->rb_right)
-               n = n->rb_right;
-       return n;
-}
-
-struct rb_node *rb_next(const struct rb_node *node)
-{
-       struct rb_node *parent;
-
-       if (rb_parent(node) == node)
-               return NULL;
-
-       /* If we have a right-hand child, go down and then left as far
-          as we can. */
-       if (node->rb_right) {
-               node = node->rb_right; 
-               while (node->rb_left)
-                       node=node->rb_left;
-               return (struct rb_node *)node;
-       }
-
-       /* No right-hand children.  Everything down and left is
-          smaller than us, so any 'next' node must be in the general
-          direction of our parent. Go up the tree; any time the
-          ancestor is a right-hand child of its parent, keep going
-          up. First time it's a left-hand child of its parent, said
-          parent is our 'next' node. */
-       while ((parent = rb_parent(node)) && node == parent->rb_right)
-               node = parent;
-
-       return parent;
-}
-
-struct rb_node *rb_prev(const struct rb_node *node)
-{
-       struct rb_node *parent;
-
-       if (rb_parent(node) == node)
-               return NULL;
-
-       /* If we have a left-hand child, go down and then right as far
-          as we can. */
-       if (node->rb_left) {
-               node = node->rb_left; 
-               while (node->rb_right)
-                       node=node->rb_right;
-               return (struct rb_node *)node;
-       }
-
-       /* No left-hand children. Go up till we find an ancestor which
-          is a right-hand child of its parent */
-       while ((parent = rb_parent(node)) && node == parent->rb_left)
-               node = parent;
-
-       return parent;
-}
-
-void rb_replace_node(struct rb_node *victim, struct rb_node *new,
-                    struct rb_root *root)
-{
-       struct rb_node *parent = rb_parent(victim);
-
-       /* Set the surrounding nodes to point to the replacement */
-       if (parent) {
-               if (victim == parent->rb_left)
-                       parent->rb_left = new;
-               else
-                       parent->rb_right = new;
-       } else {
-               root->rb_node = new;
-       }
-       if (victim->rb_left)
-               rb_set_parent(victim->rb_left, new);
-       if (victim->rb_right)
-               rb_set_parent(victim->rb_right, new);
-
-       /* Copy the pointers/colour from the victim to the replacement */
-       *new = *victim;
-}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
deleted file mode 100644 (file)
index 6bdc488..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea@suse.de>
-  
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-  linux/include/linux/rbtree.h
-
-  To use rbtrees you'll have to implement your own insert and search cores.
-  This will avoid us to use callbacks and to drop drammatically performances.
-  I know it's not the cleaner way,  but in C (not in C++) to get
-  performances and genericity...
-
-  Some example of insert and search follows here. The search is a plain
-  normal search over an ordered tree. The insert instead must be implemented
-  int two steps: as first thing the code must insert the element in
-  order as a red leaf in the tree, then the support library function
-  rb_insert_color() must be called. Such function will do the
-  not trivial work to rebalance the rbtree if necessary.
-
------------------------------------------------------------------------
-static inline struct page * rb_search_page_cache(struct inode * inode,
-                                                unsigned long offset)
-{
-       struct rb_node * n = inode->i_rb_page_cache.rb_node;
-       struct page * page;
-
-       while (n)
-       {
-               page = rb_entry(n, struct page, rb_page_cache);
-
-               if (offset < page->offset)
-                       n = n->rb_left;
-               else if (offset > page->offset)
-                       n = n->rb_right;
-               else
-                       return page;
-       }
-       return NULL;
-}
-
-static inline struct page * __rb_insert_page_cache(struct inode * inode,
-                                                  unsigned long offset,
-                                                  struct rb_node * node)
-{
-       struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
-       struct rb_node * parent = NULL;
-       struct page * page;
-
-       while (*p)
-       {
-               parent = *p;
-               page = rb_entry(parent, struct page, rb_page_cache);
-
-               if (offset < page->offset)
-                       p = &(*p)->rb_left;
-               else if (offset > page->offset)
-                       p = &(*p)->rb_right;
-               else
-                       return page;
-       }
-
-       rb_link_node(node, parent, p);
-
-       return NULL;
-}
-
-static inline struct page * rb_insert_page_cache(struct inode * inode,
-                                                unsigned long offset,
-                                                struct rb_node * node)
-{
-       struct page * ret;
-       if ((ret = __rb_insert_page_cache(inode, offset, node)))
-               goto out;
-       rb_insert_color(node, &inode->i_rb_page_cache);
- out:
-       return ret;
-}
------------------------------------------------------------------------
-*/
-
-#ifndef        _LINUX_RBTREE_H
-#define        _LINUX_RBTREE_H
-
-#include <stddef.h>
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr:       the pointer to the member.
- * @type:      the type of the container struct this is embedded in.
- * @member:    the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({                     \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
-struct rb_node
-{
-       unsigned long  rb_parent_color;
-#define        RB_RED          0
-#define        RB_BLACK        1
-       struct rb_node *rb_right;
-       struct rb_node *rb_left;
-} __attribute__((aligned(sizeof(long))));
-    /* The alignment might seem pointless, but allegedly CRIS needs it */
-
-struct rb_root
-{
-       struct rb_node *rb_node;
-};
-
-
-#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
-#define rb_color(r)   ((r)->rb_parent_color & 1)
-#define rb_is_red(r)   (!rb_color(r))
-#define rb_is_black(r) rb_color(r)
-#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
-
-static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
-{
-       rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
-       rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
-}
-
-#define RB_ROOT        (struct rb_root) { NULL, }
-#define        rb_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define RB_EMPTY_ROOT(root)    ((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node)    (rb_parent(node) == node)
-#define RB_CLEAR_NODE(node)    (rb_set_parent(node, node))
-
-extern void rb_insert_color(struct rb_node *, struct rb_root *);
-extern void rb_erase(struct rb_node *, struct rb_root *);
-
-/* Find logical next and previous nodes in a tree */
-extern struct rb_node *rb_next(const struct rb_node *);
-extern struct rb_node *rb_prev(const struct rb_node *);
-extern struct rb_node *rb_first(const struct rb_root *);
-extern struct rb_node *rb_last(const struct rb_root *);
-
-/* Fast replacement of a single node without remove/rebalance/add/rebalance */
-extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
-                           struct rb_root *root);
-
-static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
-                               struct rb_node ** rb_link)
-{
-       node->rb_parent_color = (unsigned long )parent;
-       node->rb_left = node->rb_right = NULL;
-
-       *rb_link = node;
-}
-
-#endif /* _LINUX_RBTREE_H */
index 464e7ca898cfe221eb78da21373324c90de076a0..5249d5a1b0c203176b08fce72003ea90ce114e74 100644 (file)
@@ -16,7 +16,7 @@ int prefixcmp(const char *str, const char *prefix)
  */
 char strbuf_slopbuf[1];
 
-void strbuf_init(struct strbuf *sb, size_t hint)
+void strbuf_init(struct strbuf *sb, ssize_t hint)
 {
        sb->alloc = sb->len = 0;
        sb->buf = strbuf_slopbuf;
@@ -92,7 +92,8 @@ void strbuf_ltrim(struct strbuf *sb)
 
 void strbuf_tolower(struct strbuf *sb)
 {
-       int i;
+       unsigned int i;
+
        for (i = 0; i < sb->len; i++)
                sb->buf[i] = tolower(sb->buf[i]);
 }
@@ -264,7 +265,7 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
        return res;
 }
 
-ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
+ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
 {
        size_t oldlen = sb->len;
        size_t oldalloc = sb->alloc;
@@ -293,7 +294,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
 
 #define STRBUF_MAXLINK (2*PATH_MAX)
 
-int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
+int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
 {
        size_t oldalloc = sb->alloc;
 
@@ -301,7 +302,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
                hint = 32;
 
        while (hint < STRBUF_MAXLINK) {
-               int len;
+               ssize_t len;
 
                strbuf_grow(sb, hint);
                len = readlink(path, sb->buf, hint);
@@ -343,7 +344,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
        return 0;
 }
 
-int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
+int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
 {
        int fd, len;
 
index 9ee908a3ec5d4d5329385bc10cdd676f703c0c1f..d2aa86c014c1b9a3882cfd924affaa116a122e79 100644 (file)
@@ -50,7 +50,7 @@ struct strbuf {
 #define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
 
 /*----- strbuf life cycle -----*/
-extern void strbuf_init(struct strbuf *, size_t);
+extern void strbuf_init(struct strbuf *buf, ssize_t hint);
 extern void strbuf_release(struct strbuf *);
 extern char *strbuf_detach(struct strbuf *, size_t *);
 extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
@@ -61,7 +61,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
 }
 
 /*----- strbuf size related -----*/
-static inline size_t strbuf_avail(const struct strbuf *sb) {
+static inline ssize_t strbuf_avail(const struct strbuf *sb) {
        return sb->alloc ? sb->alloc - sb->len - 1 : 0;
 }
 
@@ -122,9 +122,9 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 
 extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 /* XXX: if read fails, any partial read is undone */
-extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
-extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
+extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
+extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
 
 extern int strbuf_getline(struct strbuf *, FILE *, int);
 
index 3dca2f654cd06a31e19728fbc0d10ddb98ea4d27..bf39dfadfd24dd00fe845f1c321bf0994ad768b0 100644 (file)
@@ -5,4 +5,7 @@
 
 int hex2u64(const char *ptr, u64 *val);
 
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
 #endif
index 025a78edfffe72c11aa421abcc2d3ab252dd7d99..7ad38171dc2b9c6a6fb7c8474a1faf24101443cc 100644 (file)
@@ -64,6 +64,7 @@ int strlist__add(struct strlist *self, const char *new_entry)
 
        rb_link_node(&sn->rb_node, parent, p);
        rb_insert_color(&sn->rb_node, &self->entries);
+       ++self->nr_entries;
 
        return 0;
 }
@@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
        struct strlist *self = malloc(sizeof(*self));
 
        if (self != NULL) {
-               self->entries = RB_ROOT;
-               self->dupstr = dupstr;
+               self->entries    = RB_ROOT;
+               self->dupstr     = dupstr;
+               self->nr_entries = 0;
                if (slist && strlist__parse_list(self, slist) != 0)
                        goto out_error;
        }
@@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self)
                free(self);
        }
 }
+
+struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
+               struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
+
+               if (!idx--)
+                       return pos;
+       }
+
+       return NULL;
+}
index 2fb117fb4b6761fa55a404ee89c7b9cc70540f35..921818e44a542e9aa1f8398d950121cb39fb5c24 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef STRLIST_H_
 #define STRLIST_H_
 
-#include "rbtree.h"
+#include <linux/rbtree.h>
 #include <stdbool.h>
 
 struct str_node {
@@ -11,7 +11,8 @@ struct str_node {
 
 struct strlist {
        struct rb_root entries;
-       bool dupstr;
+       unsigned int   nr_entries;
+       bool           dupstr;
 };
 
 struct strlist *strlist__new(bool dupstr, const char *slist);
@@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn);
 int strlist__load(struct strlist *self, const char *filename);
 int strlist__add(struct strlist *self, const char *str);
 
+struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
 bool strlist__has_entry(struct strlist *self, const char *entry);
 
 static inline bool strlist__empty(const struct strlist *self)
 {
-       return rb_first(&self->entries) == NULL;
+       return self->nr_entries == 0;
+}
+
+static inline unsigned int strlist__nr_entries(const struct strlist *self)
+{
+       return self->nr_entries;
 }
 
 int strlist__parse_list(struct strlist *self, const char *s);
index 78c2efde01b7bee7a52665969cf0fcb87917b481..28106059bf12b624a309661a82373db36d017f3c 100644 (file)
@@ -6,9 +6,15 @@
 #include <libelf.h>
 #include <gelf.h>
 #include <elf.h>
+#include <bfd.h>
 
 const char *sym_hist_filter;
 
+#ifndef DMGL_PARAMS
+#define DMGL_PARAMS      (1 << 0)       /* Include function args */
+#define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
+#endif
+
 static struct symbol *symbol__new(u64 start, u64 len,
                                  const char *name, unsigned int priv_size,
                                  u64 obj_start, int verbose)
@@ -35,7 +41,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
                self = ((void *)self) + priv_size;
        }
        self->start = start;
-       self->end   = start + len - 1;
+       self->end   = len ? start + len - 1 : start;
        memcpy(self->name, name, namelen);
 
        return self;
@@ -48,8 +54,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       return fprintf(fp, " %llx-%llx %s\n",
+       if (!self->module)
+               return fprintf(fp, " %llx-%llx %s\n",
                       self->start, self->end, self->name);
+       else
+               return fprintf(fp, " %llx-%llx %s \t[%s]\n",
+                      self->start, self->end, self->name, self->module->name);
 }
 
 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -61,6 +71,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
                self->syms = RB_ROOT;
                self->sym_priv_size = sym_priv_size;
                self->find_symbol = dso__find_symbol;
+               self->slen_calculated = 0;
        }
 
        return self;
@@ -146,6 +157,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
        char *line = NULL;
        size_t n;
        FILE *file = fopen("/proc/kallsyms", "r");
+       int count = 0;
 
        if (file == NULL)
                goto out_failure;
@@ -188,8 +200,10 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
 
                if (filter && filter(self, sym))
                        symbol__delete(sym, self->sym_priv_size);
-               else
+               else {
                        dso__insert_symbol(self, sym);
+                       count++;
+               }
        }
 
        /*
@@ -212,7 +226,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
        free(line);
        fclose(file);
 
-       return 0;
+       return count;
 
 out_delete_line:
        free(line);
@@ -307,6 +321,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
               sym->st_size != 0;
 }
 
+static inline int elf_sym__is_label(const GElf_Sym *sym)
+{
+       return elf_sym__type(sym) == STT_NOTYPE &&
+               sym->st_name != 0 &&
+               sym->st_shndx != SHN_UNDEF &&
+               sym->st_shndx != SHN_ABS;
+}
+
+static inline const char *elf_sec__name(const GElf_Shdr *shdr,
+                                       const Elf_Data *secstrs)
+{
+       return secstrs->d_buf + shdr->sh_name;
+}
+
+static inline int elf_sec__is_text(const GElf_Shdr *shdr,
+                                       const Elf_Data *secstrs)
+{
+       return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
+}
+
 static inline const char *elf_sym__name(const GElf_Sym *sym,
                                        const Elf_Data *symstrs)
 {
@@ -346,36 +380,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
             idx < nr_entries; \
             ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
 
-static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
-                                      GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
-                                      GElf_Shdr *shdr_dynsym,
-                                      size_t dynsym_idx, int verbose)
+/*
+ * We need to check if we have a .dynsym, so that we can handle the
+ * .plt, synthesizing its symbols, that aren't on the symtabs (be it
+ * .dynsym or .symtab).
+ * And always look at the original dso, not at debuginfo packages, that
+ * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
+ */
+static int dso__synthesize_plt_symbols(struct  dso *self, int verbose)
 {
        uint32_t nr_rel_entries, idx;
        GElf_Sym sym;
        u64 plt_offset;
        GElf_Shdr shdr_plt;
        struct symbol *f;
-       GElf_Shdr shdr_rel_plt;
+       GElf_Shdr shdr_rel_plt, shdr_dynsym;
        Elf_Data *reldata, *syms, *symstrs;
-       Elf_Scn *scn_plt_rel, *scn_symstrs;
+       Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
+       size_t dynsym_idx;
+       GElf_Ehdr ehdr;
        char sympltname[1024];
-       int nr = 0, symidx;
+       Elf *elf;
+       int nr = 0, symidx, fd, err = 0;
+
+       fd = open(self->name, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+       if (elf == NULL)
+               goto out_close;
 
-       scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
+       if (gelf_getehdr(elf, &ehdr) == NULL)
+               goto out_elf_end;
+
+       scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
+                                        ".dynsym", &dynsym_idx);
+       if (scn_dynsym == NULL)
+               goto out_elf_end;
+
+       scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
                                          ".rela.plt", NULL);
        if (scn_plt_rel == NULL) {
-               scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
+               scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
                                                  ".rel.plt", NULL);
                if (scn_plt_rel == NULL)
-                       return 0;
+                       goto out_elf_end;
        }
 
+       err = -1;
+
        if (shdr_rel_plt.sh_link != dynsym_idx)
-               return 0;
+               goto out_elf_end;
 
-       if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
-               return 0;
+       if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
+               goto out_elf_end;
 
        /*
         * Fetch the relocation section to find the indexes to the GOT
@@ -383,19 +442,19 @@ static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
         */
        reldata = elf_getdata(scn_plt_rel, NULL);
        if (reldata == NULL)
-               return -1;
+               goto out_elf_end;
 
        syms = elf_getdata(scn_dynsym, NULL);
        if (syms == NULL)
-               return -1;
+               goto out_elf_end;
 
-       scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
+       scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
        if (scn_symstrs == NULL)
-               return -1;
+               goto out_elf_end;
 
        symstrs = elf_getdata(scn_symstrs, NULL);
        if (symstrs == NULL)
-               return -1;
+               goto out_elf_end;
 
        nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
        plt_offset = shdr_plt.sh_offset;
@@ -414,7 +473,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        sympltname, self->sym_priv_size, 0, verbose);
                        if (!f)
-                               return -1;
+                               goto out_elf_end;
 
                        dso__insert_symbol(self, f);
                        ++nr;
@@ -432,25 +491,31 @@ static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        sympltname, self->sym_priv_size, 0, verbose);
                        if (!f)
-                               return -1;
+                               goto out_elf_end;
 
                        dso__insert_symbol(self, f);
                        ++nr;
                }
-       } else {
-               /*
-                * TODO: There are still one more shdr_rel_plt.sh_type
-                * I have to investigate, but probably should be ignored.
-                */
        }
 
-       return nr;
+       err = 0;
+out_elf_end:
+       elf_end(elf);
+out_close:
+       close(fd);
+
+       if (err == 0)
+               return nr;
+out:
+       fprintf(stderr, "%s: problems reading %s PLT info.\n",
+               __func__, self->name);
+       return 0;
 }
 
 static int dso__load_sym(struct dso *self, int fd, const char *name,
-                        symbol_filter_t filter, int verbose)
+                        symbol_filter_t filter, int verbose, struct module *mod)
 {
-       Elf_Data *symstrs;
+       Elf_Data *symstrs, *secstrs;
        uint32_t nr_syms;
        int err = -1;
        uint32_t index;
@@ -458,10 +523,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        GElf_Shdr shdr;
        Elf_Data *syms;
        GElf_Sym sym;
-       Elf_Scn *sec, *sec_dynsym;
+       Elf_Scn *sec, *sec_strndx;
        Elf *elf;
-       size_t dynsym_idx;
-       int nr = 0;
+       int nr = 0, kernel = !strcmp("[kernel]", self->name);
 
        elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
        if (elf == NULL) {
@@ -477,32 +541,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                goto out_elf_end;
        }
 
-       /*
-        * We need to check if we have a .dynsym, so that we can handle the
-        * .plt, synthesizing its symbols, that aren't on the symtabs (be it
-        * .dynsym or .symtab)
-        */
-       sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
-                                        ".dynsym", &dynsym_idx);
-       if (sec_dynsym != NULL) {
-               nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
-                                                sec_dynsym, &shdr,
-                                                dynsym_idx, verbose);
-               if (nr < 0)
-                       goto out_elf_end;
-       }
-
-       /*
-        * But if we have a full .symtab (that is a superset of .dynsym) we
-        * should add the symbols not in the .dynsyn
-        */
        sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
        if (sec == NULL) {
-               if (sec_dynsym == NULL)
+               sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
+               if (sec == NULL)
                        goto out_elf_end;
-
-               sec = sec_dynsym;
-               gelf_getshdr(sec, &shdr);
        }
 
        syms = elf_getdata(sec, NULL);
@@ -517,17 +560,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        if (symstrs == NULL)
                goto out_elf_end;
 
+       sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+       if (sec_strndx == NULL)
+               goto out_elf_end;
+
+       secstrs = elf_getdata(sec_strndx, NULL);
+       if (symstrs == NULL)
+               goto out_elf_end;
+
        nr_syms = shdr.sh_size / shdr.sh_entsize;
 
        memset(&sym, 0, sizeof(sym));
-       self->prelinked = elf_section_by_name(elf, &ehdr, &shdr,
-                                             ".gnu.prelink_undo",
-                                             NULL) != NULL;
+       if (!kernel) {
+               self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+                               elf_section_by_name(elf, &ehdr, &shdr,
+                                                    ".gnu.prelink_undo",
+                                                    NULL) != NULL);
+       } else self->adjust_symbols = 0;
+
        elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
                struct symbol *f;
+               const char *name;
+               char *demangled;
                u64 obj_start;
+               struct section *section = NULL;
+               int is_label = elf_sym__is_label(&sym);
+               const char *section_name;
 
-               if (!elf_sym__is_function(&sym))
+               if (!is_label && !elf_sym__is_function(&sym))
                        continue;
 
                sec = elf_getscn(elf, sym.st_shndx);
@@ -535,9 +595,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                        goto out_elf_end;
 
                gelf_getshdr(sec, &shdr);
+
+               if (is_label && !elf_sec__is_text(&shdr, secstrs))
+                       continue;
+
+               section_name = elf_sec__name(&shdr, secstrs);
                obj_start = sym.st_value;
 
-               if (self->prelinked) {
+               if (self->adjust_symbols) {
                        if (verbose >= 2)
                                printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
                                        (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
@@ -545,15 +610,36 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
 
-               f = symbol__new(sym.st_value, sym.st_size,
-                               elf_sym__name(&sym, symstrs),
+               if (mod) {
+                       section = mod->sections->find_section(mod->sections, section_name);
+                       if (section)
+                               sym.st_value += section->vma;
+                       else {
+                               fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
+                                       mod->name, section_name);
+                               goto out_elf_end;
+                       }
+               }
+               /*
+                * We need to figure out if the object was created from C++ sources
+                * DWARF DW_compile_unit has this, but we don't always have access
+                * to it...
+                */
+               name = elf_sym__name(&sym, symstrs);
+               demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
+               if (demangled != NULL)
+                       name = demangled;
+
+               f = symbol__new(sym.st_value, sym.st_size, name,
                                self->sym_priv_size, obj_start, verbose);
+               free(demangled);
                if (!f)
                        goto out_elf_end;
 
                if (filter && filter(self, f))
                        symbol__delete(f, self->sym_priv_size);
                else {
+                       f->module = mod;
                        dso__insert_symbol(self, f);
                        nr++;
                }
@@ -577,7 +663,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
        if (!name)
                return -1;
 
-       self->prelinked = 0;
+       self->adjust_symbols = 0;
 
        if (strncmp(self->name, "/tmp/perf-", 10) == 0)
                return dso__load_perf_map(self, filter, verbose);
@@ -603,7 +689,7 @@ more:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, fd, name, filter, verbose);
+       ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
        close(fd);
 
        /*
@@ -612,11 +698,96 @@ more:
        if (!ret)
                goto more;
 
+       if (ret > 0) {
+               int nr_plt = dso__synthesize_plt_symbols(self, verbose);
+               if (nr_plt > 0)
+                       ret += nr_plt;
+       }
 out:
        free(name);
        return ret;
 }
 
+static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
+                            symbol_filter_t filter, int verbose)
+{
+       struct module *mod = mod_dso__find_module(mods, name);
+       int err = 0, fd;
+
+       if (mod == NULL || !mod->active)
+               return err;
+
+       fd = open(mod->path, O_RDONLY);
+
+       if (fd < 0)
+               return err;
+
+       err = dso__load_sym(self, fd, name, filter, verbose, mod);
+       close(fd);
+
+       return err;
+}
+
+int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
+{
+       struct mod_dso *mods = mod_dso__new_dso("modules");
+       struct module *pos;
+       struct rb_node *next;
+       int err;
+
+       err = mod_dso__load_modules(mods);
+
+       if (err <= 0)
+               return err;
+
+       /*
+        * Iterate over modules, and load active symbols.
+        */
+       next = rb_first(&mods->mods);
+       while (next) {
+               pos = rb_entry(next, struct module, rb_node);
+               err = dso__load_module(self, mods, pos->name, filter, verbose);
+
+               if (err < 0)
+                       break;
+
+               next = rb_next(&pos->rb_node);
+       }
+
+       if (err < 0) {
+               mod_dso__delete_modules(mods);
+               mod_dso__delete_self(mods);
+       }
+
+       return err;
+}
+
+static inline void dso__fill_symbol_holes(struct dso *self)
+{
+       struct symbol *prev = NULL;
+       struct rb_node *nd;
+
+       for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
+               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+
+               if (prev) {
+                       u64 hole = 0;
+                       int alias = pos->start == prev->start;
+
+                       if (!alias)
+                               hole = prev->start - pos->end - 1;
+
+                       if (hole || alias) {
+                               if (alias)
+                                       pos->end = prev->end;
+                               else if (hole)
+                                       pos->end = prev->start - 1;
+                       }
+               }
+               prev = pos;
+       }
+}
+
 static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
                             symbol_filter_t filter, int verbose)
 {
@@ -625,21 +796,28 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
        if (fd < 0)
                return -1;
 
-       err = dso__load_sym(self, fd, vmlinux, filter, verbose);
+       err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
+
+       if (err > 0)
+               dso__fill_symbol_holes(self);
+
        close(fd);
 
        return err;
 }
 
 int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose)
+                    symbol_filter_t filter, int verbose, int modules)
 {
        int err = -1;
 
-       if (vmlinux)
+       if (vmlinux) {
                err = dso__load_vmlinux(self, vmlinux, filter, verbose);
+               if (err > 0 && modules)
+                       err = dso__load_modules(self, filter, verbose);
+       }
 
-       if (err < 0)
+       if (err <= 0)
                err = dso__load_kallsyms(self, filter, verbose);
 
        return err;
index 2c48ace8203bc8d1ae0b355a74b2a34577f5a1a8..2f92b21c712d2137e3cd85df61650abcedd20be5 100644 (file)
@@ -3,8 +3,9 @@
 
 #include <linux/types.h>
 #include "types.h"
-#include "list.h"
-#include "rbtree.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include "module.h"
 
 struct symbol {
        struct rb_node  rb_node;
@@ -13,6 +14,7 @@ struct symbol {
        u64             obj_start;
        u64             hist_sum;
        u64             *hist;
+       struct module   *module;
        void            *priv;
        char            name[0];
 };
@@ -22,7 +24,8 @@ struct dso {
        struct rb_root   syms;
        struct symbol    *(*find_symbol)(struct dso *, u64 ip);
        unsigned int     sym_priv_size;
-       unsigned char    prelinked;
+       unsigned char    adjust_symbols;
+       unsigned char    slen_calculated;
        char             name[0];
 };
 
@@ -41,7 +44,8 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
 struct symbol *dso__find_symbol(struct dso *self, u64 ip);
 
 int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose);
+                    symbol_filter_t filter, int verbose, int modules);
+int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
 int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
 
 size_t dso__fprintf(struct dso *self, FILE *fp);
index b4be6071c105754a171b5a83272b07ebe300c15b..68fe157d72fb9ddae6991fdfa9b1c69ac7f51fa4 100644 (file)
@@ -50,6 +50,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/stat.h>
+#include <sys/statfs.h>
 #include <fcntl.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -80,6 +81,7 @@
 #include <netdb.h>
 #include <pwd.h>
 #include <inttypes.h>
+#include "../../../include/linux/magic.h"
 
 #ifndef NO_ICONV
 #include <iconv.h>
index 6350d65f6d9e5f8a2faca0dd40ff790bd4cda8b9..4574ac28396f6779fcecacfafe570dc0a5e01dc6 100644 (file)
@@ -7,7 +7,7 @@
  * There's no pack memory to release - but stay close to the Git
  * version so wrap this away:
  */
-static inline void release_pack_memory(size_t size, int flag)
+static inline void release_pack_memory(size_t size __used, int flag __used)
 {
 }
 
@@ -59,7 +59,8 @@ void *xmemdupz(const void *data, size_t len)
 char *xstrndup(const char *str, size_t len)
 {
        char *p = memchr(str, '\0', len);
-       return xmemdupz(str, p ? p - str : len);
+
+       return xmemdupz(str, p ? (size_t)(p - str) : len);
 }
 
 void *xrealloc(void *ptr, size_t size)