Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Mar 2010 20:39:21 +0000 (13:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Mar 2010 20:39:21 +0000 (13:39 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (45 commits)
  USB: gadget/multi: cdc_do_config: remove redundant check
  usb: r8a66597-hcd: fix removed from an attached hub
  USB: xhci: Make endpoint interval debugging clearer.
  USB: Fix usb_fill_int_urb for SuperSpeed devices
  USB: cp210x: Remove double usb_control_msg from cp210x_set_config
  USB: Remove last bit of CONFIG_USB_BERRY_CHARGE
  USB: gadget: add gadget controller number for s3c-hsotg driver
  USB: ftdi_sio: Fix locking for change_speed() function
  USB: g_mass_storage: fixed module name in Kconfig
  USB: gadget: f_mass_storage::fsg_bind(): fix error handling
  USB: g_mass_storage: fix section mismatch warnings
  USB: gadget: fix Blackfin builds after gadget cleansing
  USB: goku_udc: remove potential null dereference
  USB: option.c: Add Pirelli VID/PID and indicate Pirelli's modem interface is 0xff
  USB: serial: Fix module name typo for qcaux Kconfig entry.
  usb: cdc-wdm: Fix deadlock between write and resume
  usb: cdc-wdm: Fix order in disconnect and fix locking
  usb: cdc-wdm:Fix loss of data due to autosuspend
  usb: cdc-wdm: Fix submission of URB after suspension
  usb: cdc-wdm: Fix race between disconnect and debug messages
  ...

637 files changed:
Documentation/filesystems/ceph.txt [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt
Documentation/networking/Makefile
Documentation/networking/timestamping/Makefile
Documentation/networking/timestamping/timestamping.c
MAINTAINERS
arch/arm/Kconfig
arch/arm/boot/compressed/decompress.c
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/misc.c
arch/arm/configs/cm_t35_defconfig
arch/arm/configs/n770_defconfig
arch/arm/configs/n8x0_defconfig
arch/arm/configs/omap3_beagle_defconfig
arch/arm/configs/omap3_defconfig
arch/arm/configs/omap3_evm_defconfig
arch/arm/configs/omap3_touchbook_defconfig
arch/arm/configs/omap_3430sdp_defconfig
arch/arm/configs/omap_3630sdp_defconfig
arch/arm/configs/omap_h2_1610_defconfig
arch/arm/configs/omap_zoom2_defconfig
arch/arm/configs/omap_zoom3_defconfig
arch/arm/configs/rx51_defconfig
arch/arm/include/asm/elf.h
arch/arm/include/asm/pgtable-nommu.h
arch/arm/kernel/entry-header.S
arch/arm/kernel/kgdb.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/smp.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-zoom3.c
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/omap44xx-smc.S [new file with mode: 0644]
arch/arm/mach-omap2/prcm.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/usb-ehci.c
arch/arm/mach-rpc/include/mach/uncompress.h
arch/arm/mach-s3c2440/s3c2440-cpufreq.c [moved from arch/arm/plat-s3c24xx/s3c2440-cpufreq.c with 100% similarity]
arch/arm/mach-s3c64xx/include/mach/debug-macro.S
arch/arm/mach-s5p6440/include/mach/debug-macro.S
arch/arm/mach-s5p6442/include/mach/debug-macro.S
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g3evm.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-shmobile/clock-sh7367.c
arch/arm/mach-shmobile/intc-sh7367.c
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh7377.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/plat/blizzard.h
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/prcm.h
arch/arm/plat-omap/include/plat/system.h
arch/arm/plat-omap/include/plat/usb.h
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-samsung/include/plat/uncompress.h
arch/arm/plat-samsung/pwm.c
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/Makefile
arch/blackfin/boot/Makefile
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-EZKIT-V2_defconfig [new file with mode: 0644]
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-ACVILON_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/TCM-BF518_defconfig [new file with mode: 0644]
arch/blackfin/include/asm/bfin-lq035q1.h
arch/blackfin/include/asm/bfin_can.h [new file with mode: 0644]
arch/blackfin/include/asm/bfin_sport.h
arch/blackfin/include/asm/bfin_watchdog.h [new file with mode: 0644]
arch/blackfin/include/asm/bitops.h
arch/blackfin/include/asm/context.S
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/def_LPBlackfin.h
arch/blackfin/include/asm/delay.h
arch/blackfin/include/asm/dma-mapping.h
arch/blackfin/include/asm/dma.h
arch/blackfin/include/asm/dpmc.h
arch/blackfin/include/asm/elf.h
arch/blackfin/include/asm/ftrace.h
arch/blackfin/include/asm/gpio.h
arch/blackfin/include/asm/irq.h
arch/blackfin/include/asm/mmu_context.h
arch/blackfin/include/asm/nmi.h [new file with mode: 0644]
arch/blackfin/include/asm/page.h
arch/blackfin/include/asm/ptrace.h
arch/blackfin/include/asm/sections.h
arch/blackfin/include/asm/smp.h
arch/blackfin/include/asm/syscall.h [new file with mode: 0644]
arch/blackfin/include/asm/thread_info.h
arch/blackfin/include/asm/time.h
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/cplb-mpu/cplbinit.c
arch/blackfin/kernel/cplb-mpu/cplbmgr.c
arch/blackfin/kernel/cplb-nompu/cplbinit.c
arch/blackfin/kernel/dma-mapping.c
arch/blackfin/kernel/entry.S
arch/blackfin/kernel/ftrace-entry.S
arch/blackfin/kernel/ftrace.c
arch/blackfin/kernel/init_task.c
arch/blackfin/kernel/kgdb.c
arch/blackfin/kernel/nmi.c [new file with mode: 0644]
arch/blackfin/kernel/process.c
arch/blackfin/kernel/ptrace.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/signal.c
arch/blackfin/kernel/time-ts.c
arch/blackfin/kernel/traps.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/mach-bf518/boards/Kconfig
arch/blackfin/mach-bf518/boards/Makefile
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/boards/tcm-bf518.c [new file with mode: 0644]
arch/blackfin/mach-bf518/include/mach/irq.h
arch/blackfin/mach-bf518/include/mach/mem_map.h
arch/blackfin/mach-bf527/boards/Kconfig
arch/blackfin/mach-bf527/boards/Makefile
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/irq.h
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/ip0x.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf533/include/mach/irq.h
arch/blackfin/mach-bf537/boards/cm_bf537e.c
arch/blackfin/mach-bf537/boards/cm_bf537u.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf537/include/mach/irq.h
arch/blackfin/mach-bf538/boards/ezkit.c
arch/blackfin/mach-bf538/include/mach/irq.h
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/irq.h
arch/blackfin/mach-bf561/Makefile
arch/blackfin/mach-bf561/boards/acvilon.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/boards/tepla.c
arch/blackfin/mach-bf561/hotplug.c [new file with mode: 0644]
arch/blackfin/mach-bf561/include/mach/irq.h
arch/blackfin/mach-bf561/include/mach/smp.h
arch/blackfin/mach-bf561/secondary.S
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/head.S
arch/blackfin/mach-common/interrupt.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/smp.c
arch/blackfin/mm/isram-driver.c
arch/blackfin/mm/sram-alloc.c
arch/microblaze/Kconfig
arch/microblaze/Makefile
arch/microblaze/include/asm/device.h
arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/irq.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pci-bridge.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/prom.h
arch/microblaze/include/asm/system.h
arch/microblaze/include/asm/tlbflush.h
arch/microblaze/kernel/Makefile
arch/microblaze/kernel/asm-offsets.c
arch/microblaze/kernel/cpu/cache.c
arch/microblaze/kernel/dma.c [new file with mode: 0644]
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/head.S
arch/microblaze/kernel/irq.c
arch/microblaze/kernel/setup.c
arch/microblaze/mm/Makefile
arch/microblaze/mm/consistent.c [new file with mode: 0644]
arch/microblaze/mm/init.c
arch/microblaze/mm/pgtable.c
arch/microblaze/pci/Makefile [new file with mode: 0644]
arch/microblaze/pci/indirect_pci.c [new file with mode: 0644]
arch/microblaze/pci/iomap.c [new file with mode: 0644]
arch/microblaze/pci/pci-common.c [new file with mode: 0644]
arch/microblaze/pci/pci_32.c [new file with mode: 0644]
arch/microblaze/pci/xilinx_pci.c [new file with mode: 0644]
arch/powerpc/configs/52xx/cm5200_defconfig
arch/powerpc/configs/52xx/lite5200b_defconfig
arch/powerpc/configs/52xx/motionpro_defconfig
arch/powerpc/configs/52xx/pcm030_defconfig
arch/powerpc/configs/52xx/tqm5200_defconfig
arch/powerpc/configs/mpc5200_defconfig
arch/powerpc/kernel/perf_event.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/sh/kernel/perf_event.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/dumpstack.h
arch/x86/kernel/dumpstack_64.c
drivers/acpi/video.c
drivers/ata/ahci.c
drivers/atm/lanai.c
drivers/base/memory.c
drivers/char/hpet.c
drivers/gpu/drm/nouveau/nouveau_backlight.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-ids.h
drivers/hid/hid-magicmouse.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-tmff.c
drivers/hid/usbhid/hid-quirks.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/isdn/gigaset/capi.c
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/dummyll.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/i4l.c
drivers/isdn/gigaset/interface.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/hardware/mISDN/hfcmulti.c
drivers/isdn/hysdn/hysdn_boot.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/dell-led.c [new file with mode: 0644]
drivers/leds/led-class.c
drivers/leds/leds-gpio.c
drivers/leds/leds-ss4200.c
drivers/macintosh/via-pmu-backlight.c
drivers/md/linear.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/mtd/nand/Kconfig
drivers/net/benet/be_cmds.c
drivers/net/bnx2x_main.c
drivers/net/davinci_emac.c
drivers/net/e100.c
drivers/net/irda/w83977af_ir.c
drivers/net/ksz884x.c
drivers/net/myri10ge/myri10ge.c
drivers/net/ne.c
drivers/net/pppol2tp.c
drivers/net/s2io.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/hso.c
drivers/net/usb/smsc75xx.c [new file with mode: 0644]
drivers/net/usb/smsc75xx.h [new file with mode: 0644]
drivers/net/usb/smsc95xx.c
drivers/pci/Makefile
drivers/pcmcia/i82092.c
drivers/pcmcia/i82365.h
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/ti113x.h
drivers/pcmcia/vrc4171_card.c
drivers/pcmcia/yenta_socket.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/s390/char/sclp_cmd.c
drivers/scsi/Kconfig
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h
drivers/scsi/bfa/Makefile
drivers/scsi/bfa/bfa_core.c
drivers/scsi/bfa/bfa_fcport.c
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_port.c
drivers/scsi/bfa/bfa_fcs_uf.c
drivers/scsi/bfa/bfa_hw_cb.c
drivers/scsi/bfa/bfa_hw_ct.c
drivers/scsi/bfa/bfa_intr.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_ioc_cb.c [new file with mode: 0644]
drivers/scsi/bfa/bfa_ioc_ct.c [new file with mode: 0644]
drivers/scsi/bfa/bfa_iocfc.c
drivers/scsi/bfa/bfa_iocfc.h
drivers/scsi/bfa/bfa_ioim.c
drivers/scsi/bfa/bfa_itnim.c
drivers/scsi/bfa/bfa_lps.c
drivers/scsi/bfa/bfa_module.c
drivers/scsi/bfa/bfa_modules_priv.h
drivers/scsi/bfa/bfa_port_priv.h
drivers/scsi/bfa/bfa_priv.h
drivers/scsi/bfa/bfa_rport.c
drivers/scsi/bfa/bfa_trcmod_priv.h
drivers/scsi/bfa/bfa_tskim.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bfa/bfad_attr.h
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/bfa/bfad_intr.c
drivers/scsi/bfa/fabric.c
drivers/scsi/bfa/fcbuild.h
drivers/scsi/bfa/fcpim.c
drivers/scsi/bfa/fcs_fabric.h
drivers/scsi/bfa/fcs_fcpim.h
drivers/scsi/bfa/fcs_lport.h
drivers/scsi/bfa/fcs_port.h
drivers/scsi/bfa/fcs_rport.h
drivers/scsi/bfa/fcs_uf.h
drivers/scsi/bfa/fcs_vport.h
drivers/scsi/bfa/fdmi.c
drivers/scsi/bfa/include/aen/bfa_aen.h
drivers/scsi/bfa/include/bfa.h
drivers/scsi/bfa/include/bfa_svc.h
drivers/scsi/bfa/include/bfa_timer.h
drivers/scsi/bfa/include/bfi/bfi.h
drivers/scsi/bfa/include/bfi/bfi_cbreg.h
drivers/scsi/bfa/include/bfi/bfi_ctreg.h
drivers/scsi/bfa/include/bfi/bfi_ioc.h
drivers/scsi/bfa/include/bfi/bfi_lps.h
drivers/scsi/bfa/include/bfi/bfi_pport.h
drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h
drivers/scsi/bfa/include/cs/bfa_log.h
drivers/scsi/bfa/include/cs/bfa_plog.h
drivers/scsi/bfa/include/cs/bfa_sm.h
drivers/scsi/bfa/include/defs/bfa_defs_aen.h
drivers/scsi/bfa/include/defs/bfa_defs_auth.h
drivers/scsi/bfa/include/defs/bfa_defs_cee.h
drivers/scsi/bfa/include/defs/bfa_defs_driver.h
drivers/scsi/bfa/include/defs/bfa_defs_ethport.h
drivers/scsi/bfa/include/defs/bfa_defs_fcport.h [new file with mode: 0644]
drivers/scsi/bfa/include/defs/bfa_defs_im_common.h [deleted file]
drivers/scsi/bfa/include/defs/bfa_defs_im_team.h [deleted file]
drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
drivers/scsi/bfa/include/defs/bfa_defs_lport.h
drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
drivers/scsi/bfa/include/defs/bfa_defs_port.h
drivers/scsi/bfa/include/defs/bfa_defs_pport.h
drivers/scsi/bfa/include/defs/bfa_defs_status.h
drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h
drivers/scsi/bfa/include/fcs/bfa_fcs.h
drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
drivers/scsi/bfa/include/log/bfa_log_hal.h
drivers/scsi/bfa/include/log/bfa_log_linux.h
drivers/scsi/bfa/include/protocol/fc.h
drivers/scsi/bfa/include/protocol/pcifw.h [deleted file]
drivers/scsi/bfa/loop.c
drivers/scsi/bfa/lport_api.c
drivers/scsi/bfa/ms.c
drivers/scsi/bfa/ns.c
drivers/scsi/bfa/rport.c
drivers/scsi/bfa/rport_api.c
drivers/scsi/bfa/rport_ftrs.c
drivers/scsi/bfa/scn.c
drivers/scsi/bfa/vport.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/device_handler/scsi_dh_emc.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/hpsa_cmd.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/iseries_vscsi.c
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/libiscsi.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_bsg.h
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/osd/osd_initiator.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/raid_class.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sd.c
drivers/serial/sunsab.c
drivers/serial/uartlite.c
drivers/spi/omap2_mcspi.c
drivers/staging/samsung-laptop/samsung-laptop.c
drivers/usb/misc/appledisplay.c
drivers/video/Kconfig
drivers/video/amba-clcd.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_backlight.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adx_bl.c
drivers/video/backlight/atmel-pwm-bl.c
drivers/video/backlight/backlight.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/generic_bl.c
drivers/video/backlight/hp680_bl.c
drivers/video/backlight/jornada720_bl.c
drivers/video/backlight/kb3886_bl.c
drivers/video/backlight/l4f00242t03.c [new file with mode: 0644]
drivers/video/backlight/locomolcd.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/progear_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/wm831x_bl.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/nvidia/nv_backlight.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/riva/fbdev.c
fs/Kconfig
fs/Makefile
fs/btrfs/btrfs_inode.h
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/Kconfig [new file with mode: 0644]
fs/ceph/Makefile [new file with mode: 0644]
fs/ceph/README [new file with mode: 0644]
fs/ceph/addr.c [new file with mode: 0644]
fs/ceph/armor.c [new file with mode: 0644]
fs/ceph/auth.c [new file with mode: 0644]
fs/ceph/auth.h [new file with mode: 0644]
fs/ceph/auth_none.c [new file with mode: 0644]
fs/ceph/auth_none.h [new file with mode: 0644]
fs/ceph/auth_x.c [new file with mode: 0644]
fs/ceph/auth_x.h [new file with mode: 0644]
fs/ceph/auth_x_protocol.h [new file with mode: 0644]
fs/ceph/buffer.c [new file with mode: 0644]
fs/ceph/buffer.h [new file with mode: 0644]
fs/ceph/caps.c [new file with mode: 0644]
fs/ceph/ceph_debug.h [new file with mode: 0644]
fs/ceph/ceph_frag.c [new file with mode: 0644]
fs/ceph/ceph_frag.h [new file with mode: 0644]
fs/ceph/ceph_fs.c [new file with mode: 0644]
fs/ceph/ceph_fs.h [new file with mode: 0644]
fs/ceph/ceph_hash.c [new file with mode: 0644]
fs/ceph/ceph_hash.h [new file with mode: 0644]
fs/ceph/ceph_strings.c [new file with mode: 0644]
fs/ceph/crush/crush.c [new file with mode: 0644]
fs/ceph/crush/crush.h [new file with mode: 0644]
fs/ceph/crush/hash.c [new file with mode: 0644]
fs/ceph/crush/hash.h [new file with mode: 0644]
fs/ceph/crush/mapper.c [new file with mode: 0644]
fs/ceph/crush/mapper.h [new file with mode: 0644]
fs/ceph/crypto.c [new file with mode: 0644]
fs/ceph/crypto.h [new file with mode: 0644]
fs/ceph/debugfs.c [new file with mode: 0644]
fs/ceph/decode.h [new file with mode: 0644]
fs/ceph/dir.c [new file with mode: 0644]
fs/ceph/export.c [new file with mode: 0644]
fs/ceph/file.c [new file with mode: 0644]
fs/ceph/inode.c [new file with mode: 0644]
fs/ceph/ioctl.c [new file with mode: 0644]
fs/ceph/ioctl.h [new file with mode: 0644]
fs/ceph/mds_client.c [new file with mode: 0644]
fs/ceph/mds_client.h [new file with mode: 0644]
fs/ceph/mdsmap.c [new file with mode: 0644]
fs/ceph/mdsmap.h [new file with mode: 0644]
fs/ceph/messenger.c [new file with mode: 0644]
fs/ceph/messenger.h [new file with mode: 0644]
fs/ceph/mon_client.c [new file with mode: 0644]
fs/ceph/mon_client.h [new file with mode: 0644]
fs/ceph/msgpool.c [new file with mode: 0644]
fs/ceph/msgpool.h [new file with mode: 0644]
fs/ceph/msgr.h [new file with mode: 0644]
fs/ceph/osd_client.c [new file with mode: 0644]
fs/ceph/osd_client.h [new file with mode: 0644]
fs/ceph/osdmap.c [new file with mode: 0644]
fs/ceph/osdmap.h [new file with mode: 0644]
fs/ceph/pagelist.c [new file with mode: 0644]
fs/ceph/pagelist.h [new file with mode: 0644]
fs/ceph/rados.h [new file with mode: 0644]
fs/ceph/snap.c [new file with mode: 0644]
fs/ceph/super.c [new file with mode: 0644]
fs/ceph/super.h [new file with mode: 0644]
fs/ceph/types.h [new file with mode: 0644]
fs/ceph/xattr.c [new file with mode: 0644]
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/jffs2/readinode.c
fs/nfs/callback_xdr.c
fs/nfs/delegation.h
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/pagelist.c
fs/nfs/super.c
fs/ntfs/super.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_buf.c
include/linux/amba/clcd.h
include/linux/backlight.h
include/linux/ftrace_event.h
include/linux/memory.h
include/linux/of.h
include/linux/perf_event.h
include/linux/spi/l4f00242t03.h [new file with mode: 0644]
include/linux/syscalls.h
include/scsi/libiscsi.h
include/trace/ftrace.h
include/trace/syscall.h
kernel/kprobes.c
kernel/lockdep.c
kernel/perf_event.c
kernel/trace/Makefile
kernel/trace/trace_event_perf.c [moved from kernel/trace/trace_event_profile.c with 68% similarity]
kernel/trace/trace_events.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_syscalls.c
mm/page_cgroup.c
net/bridge/br_device.c
net/bridge/br_forward.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/core/netpoll.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/proto.c
net/ipv4/route.c
net/phonet/pn_dev.c
net/phonet/pn_netlink.c
net/sunrpc/xprtsock.c
net/tipc/ref.c
sound/oss/sequencer.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
tools/perf/Documentation/Makefile
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/util/cpumap.c [new file with mode: 0644]
tools/perf/util/cpumap.h [new file with mode: 0644]
tools/perf/util/event.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/probe-finder.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/thread.c
tools/perf/util/thread.h

diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt
new file mode 100644 (file)
index 0000000..6e03917
--- /dev/null
@@ -0,0 +1,139 @@
+Ceph Distributed File System
+============================
+
+Ceph is a distributed network file system designed to provide good
+performance, reliability, and scalability.
+
+Basic features include:
+
+ * POSIX semantics
+ * Seamless scaling from 1 to many thousands of nodes
+ * High availability and reliability.  No single points of failure.
+ * N-way replication of data across storage nodes
+ * Fast recovery from node failures
+ * Automatic rebalancing of data on node addition/removal
+ * Easy deployment: most FS components are userspace daemons
+
+Also,
+ * Flexible snapshots (on any directory)
+ * Recursive accounting (nested files, directories, bytes)
+
+In contrast to cluster filesystems like GFS, OCFS2, and GPFS that rely
+on symmetric access by all clients to shared block devices, Ceph
+separates data and metadata management into independent server
+clusters, similar to Lustre.  Unlike Lustre, however, metadata and
+storage nodes run entirely as user space daemons.  Storage nodes
+utilize btrfs to store data objects, leveraging its advanced features
+(checksumming, metadata replication, etc.).  File data is striped
+across storage nodes in large chunks to distribute workload and
+facilitate high throughputs.  When storage nodes fail, data is
+re-replicated in a distributed fashion by the storage nodes themselves
+(with some minimal coordination from a cluster monitor), making the
+system extremely efficient and scalable.
+
+Metadata servers effectively form a large, consistent, distributed
+in-memory cache above the file namespace that is extremely scalable,
+dynamically redistributes metadata in response to workload changes,
+and can tolerate arbitrary (well, non-Byzantine) node failures.  The
+metadata server takes a somewhat unconventional approach to metadata
+storage to significantly improve performance for common workloads.  In
+particular, inodes with only a single link are embedded in
+directories, allowing entire directories of dentries and inodes to be
+loaded into its cache with a single I/O operation.  The contents of
+extremely large directories can be fragmented and managed by
+independent metadata servers, allowing scalable concurrent access.
+
+The system offers automatic data rebalancing/migration when scaling
+from a small cluster of just a few nodes to many hundreds, without
+requiring an administrator carve the data set into static volumes or
+go through the tedious process of migrating data between servers.
+When the file system approaches full, new nodes can be easily added
+and things will "just work."
+
+Ceph includes flexible snapshot mechanism that allows a user to create
+a snapshot on any subdirectory (and its nested contents) in the
+system.  Snapshot creation and deletion are as simple as 'mkdir
+.snap/foo' and 'rmdir .snap/foo'.
+
+Ceph also provides some recursive accounting on directories for nested
+files and bytes.  That is, a 'getfattr -d foo' on any directory in the
+system will reveal the total number of nested regular files and
+subdirectories, and a summation of all nested file sizes.  This makes
+the identification of large disk space consumers relatively quick, as
+no 'du' or similar recursive scan of the file system is required.
+
+
+Mount Syntax
+============
+
+The basic mount syntax is:
+
+ # mount -t ceph monip[:port][,monip2[:port]...]:/[subdir] mnt
+
+You only need to specify a single monitor, as the client will get the
+full list when it connects.  (However, if the monitor you specify
+happens to be down, the mount won't succeed.)  The port can be left
+off if the monitor is using the default.  So if the monitor is at
+1.2.3.4,
+
+ # mount -t ceph 1.2.3.4:/ /mnt/ceph
+
+is sufficient.  If /sbin/mount.ceph is installed, a hostname can be
+used instead of an IP address.
+
+
+
+Mount Options
+=============
+
+  ip=A.B.C.D[:N]
+       Specify the IP and/or port the client should bind to locally.
+       There is normally not much reason to do this.  If the IP is not
+       specified, the client's IP address is determined by looking at the
+       address it's connection to the monitor originates from.
+
+  wsize=X
+       Specify the maximum write size in bytes.  By default there is no
+       maximu.  Ceph will normally size writes based on the file stripe
+       size.
+
+  rsize=X
+       Specify the maximum readahead.
+
+  mount_timeout=X
+       Specify the timeout value for mount (in seconds), in the case
+       of a non-responsive Ceph file system.  The default is 30
+       seconds.
+
+  rbytes
+       When stat() is called on a directory, set st_size to 'rbytes',
+       the summation of file sizes over all files nested beneath that
+       directory.  This is the default.
+
+  norbytes
+       When stat() is called on a directory, set st_size to the
+       number of entries in that directory.
+
+  nocrc
+       Disable CRC32C calculation for data writes.  If set, the OSD
+       must rely on TCP's error correction to detect data corruption
+       in the data payload.
+
+  noasyncreaddir
+       Disable client's use its local cache to satisfy readdir
+       requests.  (This does not change correctness; the client uses
+       cached metadata only when a lease or capability ensures it is
+       valid.)
+
+
+More Information
+================
+
+For more information on Ceph, see the home page at
+       http://ceph.newdream.net/
+
+The Linux kernel client source tree is available at
+       git://ceph.newdream.net/linux-ceph-client.git
+
+and the source for the full system is at
+       git://ceph.newdream.net/ceph.git
index 35c9b51..dd5806f 100644 (file)
@@ -291,6 +291,7 @@ Code  Seq#(hex)     Include File            Comments
 0x92   00-0F   drivers/usb/mon/mon_bin.c
 0x93   60-7F   linux/auto_fs.h
 0x94   all     fs/btrfs/ioctl.h
+0x97   00-7F   fs/ceph/ioctl.h         Ceph file system
 0x99   00-0F                           537-Addinboard driver
                                        <mailto:buk@buks.ipn.de>
 0xA0   all     linux/sdp/sdp.h         Industrial Device Project
index 6d8af1a..5aba7a3 100644 (file)
@@ -6,3 +6,5 @@ hostprogs-y := ifenslave
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
+
+obj-m := timestamping/
index 2a1489f..e799734 100644 (file)
@@ -1,6 +1,13 @@
-CPPFLAGS = -I../../../include
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
 
-timestamping: timestamping.c
+# List of programs to build
+hostprogs-y := timestamping
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
 
 clean:
        rm -f timestamping
index bab619a..8ba82bf 100644 (file)
@@ -41,9 +41,9 @@
 #include <arpa/inet.h>
 #include <net/if.h>
 
-#include "asm/types.h"
-#include "linux/net_tstamp.h"
-#include "linux/errqueue.h"
+#include <asm/types.h>
+#include <linux/net_tstamp.h>
+#include <linux/errqueue.h>
 
 #ifndef SO_TIMESTAMPING
 # define SO_TIMESTAMPING         37
@@ -164,7 +164,7 @@ static void printpacket(struct msghdr *msg, int res,
 
        gettimeofday(&now, 0);
 
-       printf("%ld.%06ld: received %s data, %d bytes from %s, %d bytes control messages\n",
+       printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
               (long)now.tv_sec, (long)now.tv_usec,
               (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
               res,
@@ -173,7 +173,7 @@ static void printpacket(struct msghdr *msg, int res,
        for (cmsg = CMSG_FIRSTHDR(msg);
             cmsg;
             cmsg = CMSG_NXTHDR(msg, cmsg)) {
-               printf("   cmsg len %d: ", cmsg->cmsg_len);
+               printf("   cmsg len %zu: ", cmsg->cmsg_len);
                switch (cmsg->cmsg_level) {
                case SOL_SOCKET:
                        printf("SOL_SOCKET ");
index 47cc449..449d444 100644 (file)
@@ -1441,6 +1441,15 @@ F:       arch/powerpc/include/asm/spu*.h
 F:     arch/powerpc/oprofile/*cell*
 F:     arch/powerpc/platforms/cell/
 
+CEPH DISTRIBUTED FILE SYSTEM CLIENT
+M:     Sage Weil <sage@newdream.net>
+L:     ceph-devel@lists.sourceforge.net
+W:     http://ceph.newdream.net/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
+S:     Supported
+F:     Documentation/filesystems/ceph.txt
+F:     fs/ceph
+
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 M:     David Vrabel <david.vrabel@csr.com>
 L:     linux-usb@vger.kernel.org
@@ -5214,6 +5223,21 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
 S:     Maintained
 F:     arch/sparc/
 
+SPARC SERIAL DRIVERS
+M:     "David S. Miller" <davem@davemloft.net>
+L:     sparclinux@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
+S:     Maintained
+F:     drivers/serial/suncore.c
+F:     drivers/serial/suncore.h
+F:     drivers/serial/sunhv.c
+F:     drivers/serial/sunsab.c
+F:     drivers/serial/sunsab.h
+F:     drivers/serial/sunsu.c
+F:     drivers/serial/sunzilog.c
+F:     drivers/serial/sunzilog.h
+
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 M:     Roger Wolff <R.E.Wolff@BitWizard.nl>
 S:     Supported
index cadfe2e..c5408bf 100644 (file)
@@ -218,6 +218,10 @@ config MMU
          Select if you want MMU-based virtualised addressing space
          support by paged memory management. If unsure, say 'Y'.
 
+#
+# The "ARM system type" choice list is ordered alphabetically by option
+# text.  Please add new entries in the option alphabetic order.
+#
 choice
        prompt "ARM system type"
        default ARCH_VERSATILE
@@ -274,6 +278,18 @@ config ARCH_AT91
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 and AT91CAP9 processors.
 
+config ARCH_BCMRING
+       bool "Broadcom BCMRING"
+       depends on MMU
+       select CPU_V6
+       select ARM_AMBA
+       select COMMON_CLKDEV
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       help
+         Support for Broadcom's BCMRing platform.
+
 config ARCH_CLPS711X
        bool "Cirrus Logic CLPS711x/EP721x-based"
        select CPU_ARM720T
@@ -359,20 +375,6 @@ config ARCH_H720X
        help
          This enables support for systems based on the Hynix HMS720x
 
-config ARCH_NOMADIK
-       bool "STMicroelectronics Nomadik"
-       select ARM_AMBA
-       select ARM_VIC
-       select CPU_ARM926T
-       select HAVE_CLK
-       select COMMON_CLKDEV
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       help
-         Support for the Nomadik platform by ST-Ericsson
-
 config ARCH_IOP13XX
        bool "IOP13xx-based"
        depends on MMU
@@ -747,6 +749,30 @@ config ARCH_U300
        help
          Support for ST-Ericsson U300 series mobile platforms.
 
+config ARCH_U8500
+       bool "ST-Ericsson U8500 Series"
+       select CPU_V7
+       select ARM_AMBA
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select COMMON_CLKDEV
+       help
+         Support for ST-Ericsson's Ux500 architecture
+
+config ARCH_NOMADIK
+       bool "STMicroelectronics Nomadik"
+       select ARM_AMBA
+       select ARM_VIC
+       select CPU_ARM926T
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Support for the Nomadik platform by ST-Ericsson
+
 config ARCH_DAVINCI
        bool "TI DaVinci"
        select CPU_ARM926T
@@ -775,30 +801,13 @@ config ARCH_OMAP
        help
          Support for TI's OMAP platform (OMAP1 and OMAP2).
 
-config ARCH_BCMRING
-       bool "Broadcom BCMRING"
-       depends on MMU
-       select CPU_V6
-       select ARM_AMBA
-       select COMMON_CLKDEV
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       select ARCH_WANT_OPTIONAL_GPIOLIB
-       help
-         Support for Broadcom's BCMRing platform.
-
-config ARCH_U8500
-       bool "ST-Ericsson U8500 Series"
-       select CPU_V7
-       select ARM_AMBA
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       select COMMON_CLKDEV
-       help
-         Support for ST-Ericsson's Ux500 architecture
-
 endchoice
 
+#
+# This is sorted alphabetically by mach-* pathname.  However, plat-*
+# Kconfigs may be included either alphabetically (according to the
+# plat- suffix) or along side the corresponding mach-* source.
+#
 source "arch/arm/mach-aaec2000/Kconfig"
 
 source "arch/arm/mach-at91/Kconfig"
index 0da382f..9c09707 100644 (file)
@@ -11,6 +11,7 @@ extern unsigned long free_mem_end_ptr;
 extern void error(char *);
 
 #define STATIC static
+#define STATIC_RW_DATA /* non-static please */
 
 #define ARCH_HAS_DECOMP_WDOG
 
index 535a91d..0f23009 100644 (file)
@@ -742,7 +742,7 @@ proc_types:
                .word   0x000f0000
                W(b)    __armv4_mmu_cache_on
                W(b)    __armv4_mmu_cache_off
-               W(b)    __armv4_mmu_cache_flush
+               W(b)    __armv5tej_mmu_cache_flush
 
                .word   0x0007b000              @ ARMv6
                .word   0x000ff000
index d32bc71..d2b2ef4 100644 (file)
@@ -33,6 +33,7 @@ unsigned int __machine_arch_type;
 #else
 
 static void putstr(const char *ptr);
+extern void error(char *x);
 
 #include <mach/uncompress.h>
 
index 893cd26..032b49b 100644 (file)
@@ -358,7 +358,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
-# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index 75cae18..de0c28a 100644 (file)
@@ -308,6 +308,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND_UP_POSSIBLE=y
 CONFIG_SUSPEND=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 
 #
 # Networking
index e6f667c..216ad00 100644 (file)
@@ -191,6 +191,7 @@ CONFIG_ARCH_OMAP=y
 #
 CONFIG_ARCH_OMAP_OTG=y
 # CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2PLUS=y
 CONFIG_ARCH_OMAP2=y
 # CONFIG_ARCH_OMAP3 is not set
 # CONFIG_ARCH_OMAP4 is not set
@@ -198,8 +199,6 @@ CONFIG_ARCH_OMAP2=y
 #
 # OMAP Feature Selections
 #
-# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
-# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
 CONFIG_OMAP_RESET_CLOCKS=y
 # CONFIG_OMAP_MUX is not set
 # CONFIG_OMAP_MCBSP is not set
@@ -208,15 +207,13 @@ CONFIG_OMAP_MBOX_FWK=y
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_32K_TIMER_HZ=128
 CONFIG_OMAP_DM_TIMER=y
-# CONFIG_OMAP_LL_DEBUG_UART1 is not set
-# CONFIG_OMAP_LL_DEBUG_UART2 is not set
-CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
 # CONFIG_MACH_OMAP_GENERIC is not set
 
 #
 # OMAP Core Type
 #
-CONFIG_ARCH_OMAP24XX=y
 CONFIG_ARCH_OMAP2420=y
 # CONFIG_ARCH_OMAP2430 is not set
 
@@ -227,6 +224,9 @@ CONFIG_MACH_OMAP2_TUSB6010=y
 # CONFIG_MACH_OMAP_H4 is not set
 # CONFIG_MACH_OMAP_APOLLON is not set
 # CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_NOKIA_N800=y
+CONFIG_MACH_NOKIA_N810=y
+CONFIG_MACH_NOKIA_N810_WIMAX=y
 CONFIG_MACH_NOKIA_N8X0=y
 
 #
@@ -303,7 +303,7 @@ CONFIG_ALIGNMENT_TRAP=y
 CONFIG_ZBOOT_ROM_TEXT=0x10C08000
 CONFIG_ZBOOT_ROM_BSS=0x10200000
 # CONFIG_ZBOOT_ROM is not set
-CONFIG_CMDLINE="root=1f03 rootfstype=jffs2 console=ttyS2,115200n8"
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 console=ttyS2,115200n8 debug earlyprintk rootwait"
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
@@ -337,7 +337,14 @@ CONFIG_HAVE_AOUT=y
 #
 # Power management options
 #
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
@@ -617,7 +624,55 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_SMBUS is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 CONFIG_SPI=y
 # CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
@@ -673,15 +728,44 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+CONFIG_MENELAUS=y
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
 # CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
 # CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_DUMMY is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
 #
@@ -718,7 +802,10 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
 # CONFIG_USB_MON is not set
 # CONFIG_USB_WUSB is not set
 # CONFIG_USB_WUSB_CBAF is not set
@@ -737,9 +824,10 @@ CONFIG_USB_DEVICE_CLASS=y
 CONFIG_USB_MUSB_HDRC=y
 CONFIG_USB_TUSB6010=y
 # CONFIG_USB_MUSB_HOST is not set
-CONFIG_USB_MUSB_PERIPHERAL=y
-# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
 CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
 # CONFIG_MUSB_PIO_ONLY is not set
 # CONFIG_USB_INVENTRA_DMA is not set
 # CONFIG_USB_TI_CPPI_DMA is not set
@@ -824,44 +912,77 @@ CONFIG_USB_GADGET_DUALSPEED=y
 # CONFIG_USB_ZERO is not set
 # CONFIG_USB_AUDIO is not set
 CONFIG_USB_ETH=y
-# CONFIG_USB_ETH_RNDIS is not set
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_ETH_EEM=y
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_MULTI is not set
 
 #
 # OTG and related infrastructure
 #
 CONFIG_USB_OTG_UTILS=y
 # CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_USB_ULPI is not set
 CONFIG_NOP_USB_XCEIV=y
-# CONFIG_MMC is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
 # File systems
 #
 # CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
 # CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_FILE_LOCKING=y
 CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
@@ -886,8 +1007,11 @@ CONFIG_INOTIFY_USER=y
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=y
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
index c7999f5..5a9e95f 100644 (file)
@@ -324,6 +324,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index 714835e..d6ad921 100644 (file)
@@ -450,7 +450,7 @@ CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
-# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index e2ad859..a6dd6d1 100644 (file)
@@ -340,6 +340,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index 74fe6be..968fbaa 100644 (file)
@@ -368,7 +368,7 @@ CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
-# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index bb2917e..ddde429 100644 (file)
@@ -363,6 +363,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index d25c3d4..609f348 100644 (file)
@@ -361,7 +361,7 @@ CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
-# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index 5231895..91ef2ed 100644 (file)
@@ -331,6 +331,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 
 #
index a82e813..f5c6e11 100644 (file)
@@ -343,6 +343,7 @@ CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index ff8ac3d..ea9a501 100644 (file)
@@ -361,7 +361,7 @@ CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
-# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index 193bd33..45135ff 100644 (file)
@@ -322,6 +322,7 @@ CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
index a399bb5..bff0564 100644 (file)
@@ -98,6 +98,7 @@ extern int elf_check_arch(const struct elf32_hdr *);
 extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
 #define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
 
+struct task_struct;
 int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
 #define ELF_CORE_COPY_TASK_REGS dump_task_regs
 
index 013cfcd..ffc0e85 100644 (file)
@@ -67,6 +67,7 @@ static inline int pte_file(pte_t pte) { return 0; }
  */
 #define pgprot_noncached(prot) __pgprot(0)
 #define pgprot_writecombine(prot) __pgprot(0)
+#define pgprot_dmacoherent(prot) __pgprot(0)
 
 
 /*
index 7e9ed1e..d93f976 100644 (file)
        .else
        ldmdb   sp, {r0 - lr}^                  @ get calling r0 - lr
        .endif
+       mov     r0, r0                          @ ARMv5T and earlier require a nop
+                                               @ after ldm {}^
        add     sp, sp, #S_FRAME_SIZE - S_PC
        movs    pc, lr                          @ return & move spsr_svc into cpsr
        .endm
index ba8ccfe..a5b846b 100644 (file)
@@ -9,6 +9,7 @@
  * Authors:  George Davis <davis_g@mvista.com>
  *           Deepak Saxena <dsaxena@plexity.net>
  */
+#include <linux/irq.h>
 #include <linux/kgdb.h>
 #include <asm/traps.h>
 
@@ -158,6 +159,18 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
        .fn                     = kgdb_compiled_brk_fn
 };
 
+static void kgdb_call_nmi_hook(void *ignored)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       local_irq_enable();
+       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+       local_irq_disable();
+}
+
 /**
  *     kgdb_arch_init - Perform any architecture specific initalization.
  *
index 3875d99..9e70f20 100644 (file)
@@ -332,7 +332,8 @@ armpmu_reserve_hardware(void)
 
        for (i = 0; i < pmu_irqs->num_irqs; ++i) {
                err = request_irq(pmu_irqs->irqs[i], armpmu->handle_irq,
-                                 IRQF_DISABLED, "armpmu", NULL);
+                                 IRQF_DISABLED | IRQF_NOBALANCING,
+                                 "armpmu", NULL);
                if (err) {
                        pr_warning("unable to request IRQ%d for ARM "
                                   "perf counters\n", pmu_irqs->irqs[i]);
@@ -1624,7 +1625,7 @@ enum armv7_counters {
 /*
  * EVTSEL: Event selection reg
  */
-#define        ARMV7_EVTSEL_MASK       0x7f            /* Mask for writable bits */
+#define        ARMV7_EVTSEL_MASK       0xff            /* Mask for writable bits */
 
 /*
  * SELECT: Counter selection reg
index 57162af..577543f 100644 (file)
@@ -99,6 +99,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
        *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
                     PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
        flush_pmd_entry(pmd);
+       outer_clean_range(__pa(pmd), __pa(pmd + 1));
 
        /*
         * We need to tell the secondary core where to find
@@ -106,7 +107,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
         */
        secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
        secondary_data.pgdir = virt_to_phys(pgd);
-       wmb();
+       __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
+       outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
 
        /*
         * Now bring the CPU into our world.
index 29cf831..c11fd47 100644 (file)
@@ -271,10 +271,12 @@ static void __init ek_add_device_buttons(void) {}
 
 
 static struct i2c_board_info __initdata ek_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("24c512", 0x50),
-               I2C_BOARD_INFO("wm8731", 0x1b),
-       },
+        {
+                I2C_BOARD_INFO("24c512", 0x50)
+        },
+        {
+                I2C_BOARD_INFO("wm8731", 0x1b)
+        },
 };
 
 
index 2069fb3..4b9fc57 100644 (file)
@@ -22,6 +22,9 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 # SMP support ONLY available for OMAP4
 obj-$(CONFIG_SMP)                      += omap-smp.o omap-headsmp.o
 obj-$(CONFIG_LOCAL_TIMERS)             += timer-mpu.o
+obj-$(CONFIG_ARCH_OMAP4)               += omap44xx-smc.o
+
+AFLAGS_omap44xx-smc.o                  :=-Wa,-march=armv7-a
 
 # Functions loaded to SRAM
 obj-$(CONFIG_ARCH_OMAP2420)            += sram242x.o
index a101029..5822bcf 100644 (file)
@@ -648,7 +648,7 @@ static void enable_board_wakeup_source(void)
                OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
 }
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
index 4386d2b..a0a2a11 100644 (file)
@@ -54,7 +54,7 @@ static void enable_board_wakeup_source(void)
                OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
 }
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
index 180ac11..b88f28c 100644 (file)
@@ -50,33 +50,9 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = {
 };
 
 #ifdef CONFIG_CACHE_L2X0
-noinline void omap_smc1(u32 fn, u32 arg)
-{
-       register u32 r12 asm("r12") = fn;
-       register u32 r0 asm("r0") = arg;
-
-       /* This is common routine cache secure monitor API used to
-        * modify the PL310 secure registers.
-        * r0 contains the value to be modified and "r12" contains
-        * the monitor API number. It uses few CPU registers
-        * internally and hence they need be backed up including
-        * link register "lr".
-        * Explicitly save r11 and r12 the compiler generated code
-        * won't save it.
-        */
-       asm volatile(
-               "stmfd r13!, {r11,r12}\n"
-               "dsb\n"
-               "smc\n"
-               "ldmfd r13!, {r11,r12}\n"
-               : "+r" (r0), "+r" (r12)
-               :
-               : "r4", "r5", "r10", "lr", "cc");
-}
-EXPORT_SYMBOL(omap_smc1);
-
 static int __init omap_l2_cache_init(void)
 {
+       extern void omap_smc1(u32 fn, u32 arg);
        void __iomem *l2cache_base;
 
        /* To avoid code running on other OMAPs in
index 70c1861..6ae8805 100644 (file)
@@ -273,7 +273,7 @@ static void __init am3517_evm_init_irq(void)
        omap_gpio_init();
 }
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
index afa77ca..2de4f79 100644 (file)
@@ -612,7 +612,7 @@ static struct omap2_hsmmc_info mmc[] = {
        {}      /* Terminator */
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata = {
+static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
index 3710190..5bfc13b 100644 (file)
@@ -636,7 +636,7 @@ static struct omap_musb_board_data musb_board_data = {
        .power                  = 100,
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
index 9958987..3c7789d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/leds.h>
 #include <linux/interrupt.h>
 
 #include <linux/regulator/machine.h>
@@ -39,8 +38,8 @@
 #define IGEP2_SMSC911X_CS       5
 #define IGEP2_SMSC911X_GPIO     176
 #define IGEP2_GPIO_USBH_NRESET  24
-#define IGEP2_GPIO_LED0_RED    26
-#define IGEP2_GPIO_LED0_GREEN  27
+#define IGEP2_GPIO_LED0_GREEN  26
+#define IGEP2_GPIO_LED0_RED    27
 #define IGEP2_GPIO_LED1_RED    28
 #define IGEP2_GPIO_DVI_PUP     170
 #define IGEP2_GPIO_WIFI_NPD    94
@@ -355,34 +354,50 @@ static void __init igep2_display_init(void)
            gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1))
                pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
 }
-#ifdef CONFIG_LEDS_TRIGGERS
-static struct gpio_led gpio_leds[] = {
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep2_gpio_leds[] = {
        {
-               .name = "GPIO_LED1_RED",
+               .name = "led0:red",
+               .gpio = IGEP2_GPIO_LED0_RED,
+       },
+       {
+               .name = "led0:green",
                .default_trigger = "heartbeat",
+               .gpio = IGEP2_GPIO_LED0_GREEN,
+       },
+       {
+               .name = "led1:red",
                .gpio = IGEP2_GPIO_LED1_RED,
        },
 };
 
-static struct gpio_led_platform_data gpio_leds_info = {
-       .leds           = gpio_leds,
-       .num_leds       = ARRAY_SIZE(gpio_leds),
+static struct gpio_led_platform_data igep2_led_pdata = {
+       .leds           = igep2_gpio_leds,
+       .num_leds       = ARRAY_SIZE(igep2_gpio_leds),
 };
 
-static struct platform_device leds_gpio = {
+static struct platform_device igep2_led_device = {
         .name   = "leds-gpio",
         .id     = -1,
         .dev    = {
-                .platform_data  =  &gpio_leds_info,
+                .platform_data  =  &igep2_led_pdata,
        },
 };
+
+static void __init igep2_init_led(void)
+{
+       platform_device_register(&igep2_led_device);
+}
+
+#else
+static inline void igep2_init_led(void) {}
 #endif
 
 static struct platform_device *igep2_devices[] __initdata = {
        &igep2_dss_device,
-#ifdef CONFIG_LEDS_TRIGGERS
-       &leds_gpio,
-#endif
 };
 
 static void __init igep2_init_irq(void)
@@ -442,7 +457,7 @@ static struct omap_musb_board_data musb_board_data = {
        .power                  = 100,
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
        .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
@@ -471,31 +486,34 @@ static void __init igep2_init(void)
        usb_ehci_init(&ehci_pdata);
 
        igep2_flash_init();
+       igep2_init_led();
        igep2_display_init();
        igep2_init_smsc911x();
 
        /* GPIO userspace leds */
-       if ((gpio_request(IGEP2_GPIO_LED0_RED, "GPIO_LED0_RED") == 0) &&
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+       if ((gpio_request(IGEP2_GPIO_LED0_RED, "led0:red") == 0) &&
            (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
                gpio_export(IGEP2_GPIO_LED0_RED, 0);
                gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
        } else
                pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
 
-       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "GPIO_LED0_GREEN") == 0) &&
+       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "led0:green") == 0) &&
            (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
                gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
                gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
        } else
                pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
-#ifndef CONFIG_LEDS_TRIGGERS
-       if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_LED1_RED") == 0) &&
+
+       if ((gpio_request(IGEP2_GPIO_LED1_RED, "led1:red") == 0) &&
            (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
                gpio_export(IGEP2_GPIO_LED1_RED, 0);
                gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
        } else
                pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
 #endif
+
        /* GPIO W-LAN + Bluetooth combo module */
        if ((gpio_request(IGEP2_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
            (gpio_direction_output(IGEP2_GPIO_WIFI_NPD, 1) == 0)) {
index 4cab052..da9bcb8 100644 (file)
@@ -37,6 +37,103 @@ static int slot1_cover_open;
 static int slot2_cover_open;
 static struct device *mmc_device;
 
+#define TUSB6010_ASYNC_CS      1
+#define TUSB6010_SYNC_CS       4
+#define TUSB6010_GPIO_INT      58
+#define TUSB6010_GPIO_ENABLE   0
+#define TUSB6010_DMACHAN       0x3f
+
+#if defined(CONFIG_USB_TUSB6010) || \
+       defined(CONFIG_USB_TUSB6010_MODULE)
+/*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+static int tusb_set_power(int state)
+{
+       int i, retval = 0;
+
+       if (state) {
+               gpio_set_value(TUSB6010_GPIO_ENABLE, 1);
+               msleep(1);
+
+               /* Wait until TUSB6010 pulls INT pin down */
+               i = 100;
+               while (i && gpio_get_value(TUSB6010_GPIO_INT)) {
+                       msleep(1);
+                       i--;
+               }
+
+               if (!i) {
+                       printk(KERN_ERR "tusb: powerup failed\n");
+                       retval = -ENODEV;
+               }
+       } else {
+               gpio_set_value(TUSB6010_GPIO_ENABLE, 0);
+               msleep(10);
+       }
+
+       return retval;
+}
+
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 1,
+       .dyn_fifo       = 1,
+       .num_eps        = 16,
+       .ram_bits       = 12,
+};
+
+static struct musb_hdrc_platform_data tusb_data = {
+#if defined(CONFIG_USB_MUSB_OTG)
+       .mode           = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+       .mode           = MUSB_PERIPHERAL,
+#else /* defined(CONFIG_USB_MUSB_HOST) */
+       .mode           = MUSB_HOST,
+#endif
+       .set_power      = tusb_set_power,
+       .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+       .power          = 100,  /* Max 100 mA VBUS for host mode */
+       .config         = &musb_config,
+};
+
+static void __init n8x0_usb_init(void)
+{
+       int ret = 0;
+       static char     announce[] __initdata = KERN_INFO "TUSB 6010\n";
+
+       /* PM companion chip power control pin */
+       ret = gpio_request(TUSB6010_GPIO_ENABLE, "TUSB6010 enable");
+       if (ret != 0) {
+               printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
+                      TUSB6010_GPIO_ENABLE);
+               return;
+       }
+       gpio_direction_output(TUSB6010_GPIO_ENABLE, 0);
+
+       tusb_set_power(0);
+
+       ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
+                                       TUSB6010_ASYNC_CS, TUSB6010_SYNC_CS,
+                                       TUSB6010_GPIO_INT, TUSB6010_DMACHAN);
+       if (ret != 0)
+               goto err;
+
+       printk(announce);
+
+       return;
+
+err:
+       gpio_free(TUSB6010_GPIO_ENABLE);
+}
+#else
+
+static void __init n8x0_usb_init(void) {}
+
+#endif /*CONFIG_USB_TUSB6010 */
+
+
 static struct omap2_mcspi_device_config p54spi_mcspi_config = {
        .turbo_mode     = 0,
        .single_channel = 1,
@@ -562,6 +659,7 @@ static void __init n8x0_init_machine(void)
        n8x0_menelaus_init();
        n8x0_onenand_init();
        n8x0_mmc_init();
+       n8x0_usb_init();
 }
 
 MACHINE_START(NOKIA_N800, "Nokia N800")
index 6eb77e1..962d377 100644 (file)
@@ -410,7 +410,7 @@ static void __init omap3beagle_flash_init(void)
        }
 }
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
index d6bc88c..017bb2f 100644 (file)
@@ -635,7 +635,7 @@ static struct platform_device *omap3_evm_devices[] __initdata = {
        &omap3_evm_dss_device,
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
index 4827f46..395d049 100644 (file)
@@ -459,12 +459,20 @@ static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
        },
 };
 
+static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("bq27500", 0x55),
+               .flags = I2C_CLIENT_WAKE,
+       },
+};
+
 static int __init omap3pandora_i2c_init(void)
 {
        omap_register_i2c_bus(1, 2600, omap3pandora_i2c_boardinfo,
                        ARRAY_SIZE(omap3pandora_i2c_boardinfo));
        /* i2c2 pins are not connected */
-       omap_register_i2c_bus(3, 100, NULL, 0);
+       omap_register_i2c_bus(3, 100, omap3pandora_i2c3_boardinfo,
+                       ARRAY_SIZE(omap3pandora_i2c3_boardinfo));
        return 0;
 }
 
@@ -537,7 +545,7 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
        &pandora_dss_device,
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
index 3943d0f..2504d41 100644 (file)
@@ -493,7 +493,7 @@ static void __init omap3touchbook_flash_init(void)
        }
 }
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
        .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
@@ -518,14 +518,14 @@ static void omap3_touchbook_poweroff(void)
        gpio_direction_output(TB_KILL_POWER_GPIO, 0);
 }
 
-static void __init early_touchbook_revision(char **p)
+static int __init early_touchbook_revision(char *p)
 {
-       if (!*p)
-               return;
+       if (!p)
+               return 0;
 
-       strict_strtoul(*p, 10, &touchbook_revision);
+       return strict_strtoul(p, 10, &touchbook_revision);
 }
-__early_param("tbr=", early_touchbook_revision);
+early_param("tbr", early_touchbook_revision);
 
 static struct omap_musb_board_data musb_board_data = {
        .interface_type         = MUSB_INTERFACE_ULPI,
index 50872a4..8848c7c 100644 (file)
@@ -394,7 +394,7 @@ static struct platform_device *overo_devices[] __initdata = {
        &overo_lcd_device,
 };
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
        .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
        .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
index d3e3cd5..cd3e40c 100644 (file)
@@ -52,7 +52,7 @@ static struct omap_board_mux board_mux[] __initdata = {
 #define board_mux      NULL
 #endif
 
-static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
        .port_mode[0]           = EHCI_HCD_OMAP_MODE_UNKNOWN,
        .port_mode[1]           = EHCI_HCD_OMAP_MODE_PHY,
        .port_mode[2]           = EHCI_HCD_OMAP_MODE_UNKNOWN,
index f12af95..d932b14 100644 (file)
@@ -1841,6 +1841,7 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "aes_ick",      &aes_ick,       CK_242X),
        CLK(NULL,       "pka_ick",      &pka_ick,       CK_242X),
        CLK(NULL,       "usb_fck",      &usb_fck,       CK_242X),
+       CLK("musb_hdrc",        "fck",  &osc_ck,        CK_242X),
 };
 
 /*
index 402e8f0..87f676a 100644 (file)
@@ -237,7 +237,7 @@ static void __init _omap2_map_common_io(void)
 }
 
 #ifdef CONFIG_ARCH_OMAP2420
-void __init omap242x_map_common_io()
+void __init omap242x_map_common_io(void)
 {
        iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
        iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
@@ -246,7 +246,7 @@ void __init omap242x_map_common_io()
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2430
-void __init omap243x_map_common_io()
+void __init omap243x_map_common_io(void)
 {
        iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
        iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc));
@@ -255,7 +255,7 @@ void __init omap243x_map_common_io()
 #endif
 
 #ifdef CONFIG_ARCH_OMAP3
-void __init omap34xx_map_common_io()
+void __init omap34xx_map_common_io(void)
 {
        iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
        _omap2_map_common_io();
@@ -263,7 +263,7 @@ void __init omap34xx_map_common_io()
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
-void __init omap44xx_map_common_io()
+void __init omap44xx_map_common_io(void)
 {
        iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc));
        _omap2_map_common_io();
@@ -309,7 +309,6 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
 {
        pwrdm_init(powerdomains_omap);
        clkdm_init(clockdomains_omap, clkdm_autodeps);
-#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */
        if (cpu_is_omap242x())
                omap2420_hwmod_init();
        else if (cpu_is_omap243x())
@@ -319,7 +318,6 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
        omap2_mux_init();
        /* The OPP tables have to be registered before a clk init */
        omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
-#endif
 
        if (cpu_is_omap2420())
                omap2420_clk_init();
@@ -333,11 +331,12 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
                pr_err("Could not init clock framework - unknown CPU\n");
 
        omap_serial_early_init();
-#ifndef CONFIG_ARCH_OMAP4
-       omap_hwmod_late_init();
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())   /* FIXME: OMAP4 */
+               omap_hwmod_late_init();
        omap_pm_if_init();
-       omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
-       _omap2_init_reprogram_sdrc();
-#endif
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
+               _omap2_init_reprogram_sdrc();
+       }
        gpmc_init();
 }
index 52a981c..318f363 100644 (file)
@@ -430,19 +430,19 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
                if (unlikely(!res)) {
                        dev_err(&pdev->dev, "invalid irq resource\n");
                        ret = -ENODEV;
-                       goto err_iva1;
+                       omap_mbox_unregister(&mbox_dsp_info);
+                       goto err_dsp;
                }
                mbox_iva_info.irq = res->start;
                ret = omap_mbox_register(&pdev->dev, &mbox_iva_info);
-               if (ret)
-                       goto err_iva1;
+               if (ret) {
+                       omap_mbox_unregister(&mbox_dsp_info);
+                       goto err_dsp;
+               }
        }
 #endif
        return 0;
 
-err_iva1:
-       omap_mbox_unregister(&mbox_dsp_info);
-
 err_dsp:
        iounmap(mbox_base);
        return ret;
diff --git a/arch/arm/mach-omap2/omap44xx-smc.S b/arch/arm/mach-omap2/omap44xx-smc.S
new file mode 100644 (file)
index 0000000..89bb2b1
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * OMAP44xx secure APIs file.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Written by Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ *
+ * This program is free software,you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * This is common routine to manage secure monitor API
+ * used to modify the PL310 secure registers.
+ * 'r0' contains the value to be modified and 'r12' contains
+ * the monitor API number. It uses few CPU registers
+ * internally and hence they need be backed up including
+ * link register "lr".
+ * Function signature : void omap_smc1(u32 fn, u32 arg)
+ */
+
+ENTRY(omap_smc1)
+       stmfd   sp!, {r2-r12, lr}
+       mov     r12, r0
+       mov     r0, r1
+       dsb
+       smc
+       ldmfd   sp!, {r2-r12, pc}
+END(omap_smc1)
index 81872aa..9537f6f 100644 (file)
@@ -133,7 +133,7 @@ u32 omap_prcm_get_reset_sources(void)
 EXPORT_SYMBOL(omap_prcm_get_reset_sources);
 
 /* Resets clock rates and reboots the system. Only called from system.h */
-void omap_prcm_arch_reset(char mode)
+void omap_prcm_arch_reset(char mode, const char *cmd)
 {
        s16 prcm_offs = 0;
 
@@ -145,7 +145,7 @@ void omap_prcm_arch_reset(char mode)
                u32 l;
 
                prcm_offs = OMAP3430_GR_MOD;
-               l = ('B' << 24) | ('M' << 16) | mode;
+               l = ('B' << 24) | ('M' << 16) | (cmd ? (u8)*cmd : 0);
                /* Reserve the first word in scratchpad for communicating
                 * with the boot ROM. A pointer to a data structure
                 * describing the boot process can be stored there,
index b79bc89..da77930 100644 (file)
@@ -644,16 +644,21 @@ static void serial_out_override(struct uart_port *up, int offset, int value)
 }
 void __init omap_serial_early_init(void)
 {
-       int i;
+       int i, nr_ports;
        char name[16];
 
+       if (!(cpu_is_omap3630() || cpu_is_omap4430()))
+               nr_ports = 3;
+       else
+               nr_ports = ARRAY_SIZE(omap_uart);
+
        /*
         * Make sure the serial ports are muxed on at this point.
         * You have to mux them off in device drivers later on
         * if not needed.
         */
 
-       for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
+       for (i = 0; i < nr_ports; i++) {
                struct omap_uart_state *uart = &omap_uart[i];
                struct platform_device *pdev = &uart->pdev;
                struct device *dev = &pdev->dev;
@@ -669,17 +674,17 @@ void __init omap_serial_early_init(void)
                        continue;
                }
 
-               sprintf(name, "uart%d_ick", i+1);
+               sprintf(name, "uart%d_ick", i + 1);
                uart->ick = clk_get(NULL, name);
                if (IS_ERR(uart->ick)) {
-                       printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
+                       printk(KERN_ERR "Could not get uart%d_ick\n", i + 1);
                        uart->ick = NULL;
                }
 
                sprintf(name, "uart%d_fck", i+1);
                uart->fck = clk_get(NULL, name);
                if (IS_ERR(uart->fck)) {
-                       printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
+                       printk(KERN_ERR "Could not get uart%d_fck\n", i + 1);
                        uart->fck = NULL;
                }
 
index f1df873..ee9f548 100644 (file)
@@ -70,7 +70,7 @@ static struct platform_device ehci_device = {
 /*
  * setup_ehci_io_mux - initialize IO pad mux for USBHOST
  */
-static void setup_ehci_io_mux(enum ehci_hcd_omap_mode *port_mode)
+static void setup_ehci_io_mux(const enum ehci_hcd_omap_mode *port_mode)
 {
        switch (port_mode[0]) {
        case EHCI_HCD_OMAP_MODE_PHY:
@@ -213,7 +213,7 @@ static void setup_ehci_io_mux(enum ehci_hcd_omap_mode *port_mode)
        return;
 }
 
-void __init usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata)
+void __init usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata)
 {
        platform_device_add_data(&ehci_device, pdata, sizeof(*pdata));
 
@@ -229,7 +229,7 @@ void __init usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata)
 
 #else
 
-void __init usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata)
+void __init usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata)
 
 {
 }
index d586236..8c9e2c7 100644 (file)
@@ -109,8 +109,6 @@ static inline void flush(void)
 {
 }
 
-static void error(char *x);
-
 /*
  * Setup for decompression
  */
index b18ac52..f9ab5d2 100644 (file)
@@ -21,7 +21,7 @@
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx
+       .macro addruart, rx, rtmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
index 48cdb0d..1347d7f 100644 (file)
@@ -19,7 +19,7 @@
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx
+       .macro addruart, rx, rtmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
index 1aae691..bb65361 100644 (file)
@@ -15,7 +15,7 @@
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-       .macro addruart, rx
+       .macro addruart, rx, rtmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
index a0463d9..1c2ec96 100644 (file)
@@ -206,10 +206,32 @@ static struct platform_device keysc_device = {
        },
 };
 
+/* SDHI0 */
+static struct resource sdhi0_resources[] = {
+       [0] = {
+               .name   = "SDHI0",
+               .start  = 0xe6850000,
+               .end    = 0xe68501ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 96,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi0_device = {
+       .name           = "sh_mobile_sdhi",
+       .num_resources  = ARRAY_SIZE(sdhi0_resources),
+       .resource       = sdhi0_resources,
+       .id             = 0,
+};
+
 static struct platform_device *ap4evb_devices[] __initdata = {
        &nor_flash_device,
        &smc911x_device,
        &keysc_device,
+       &sdhi0_device,
 };
 
 static struct map_desc ap4evb_io_desc[] __initdata = {
@@ -286,6 +308,16 @@ static void __init ap4evb_init(void)
        gpio_request(GPIO_FN_KEYIN3_133, NULL);
        gpio_request(GPIO_FN_KEYIN4,     NULL);
 
+       /* SDHI0 */
+       gpio_request(GPIO_FN_SDHICD0, NULL);
+       gpio_request(GPIO_FN_SDHIWP0, NULL);
+       gpio_request(GPIO_FN_SDHICMD0, NULL);
+       gpio_request(GPIO_FN_SDHICLK0, NULL);
+       gpio_request(GPIO_FN_SDHID0_3, NULL);
+       gpio_request(GPIO_FN_SDHID0_2, NULL);
+       gpio_request(GPIO_FN_SDHID0_1, NULL);
+       gpio_request(GPIO_FN_SDHID0_0, NULL);
+
        sh7372_add_standard_devices();
 
        platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices));
index f36c9a9..9247503 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mtd/sh_flctl.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
 #include <mach/sh7367.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
@@ -127,9 +130,90 @@ static struct platform_device usb_host_device = {
        .resource       = usb_host_resources,
 };
 
+/* KEYSC */
+static struct sh_keysc_info keysc_info = {
+       .mode           = SH_KEYSC_MODE_5,
+       .scan_timing    = 3,
+       .delay          = 100,
+       .keycodes = {
+               KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
+               KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N,
+               KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U,
+               KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_HOME, KEY_SLEEP,
+               KEY_WAKEUP, KEY_COFFEE, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
+               KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_STOP, KEY_COMPUTER,
+       },
+};
+
+static struct resource keysc_resources[] = {
+       [0] = {
+               .name   = "KEYSC",
+               .start  = 0xe61b0000,
+               .end    = 0xe61b000f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 79,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device keysc_device = {
+       .name           = "sh_keysc",
+       .num_resources  = ARRAY_SIZE(keysc_resources),
+       .resource       = keysc_resources,
+       .dev    = {
+               .platform_data  = &keysc_info,
+       },
+};
+
+static struct mtd_partition nand_partition_info[] = {
+       {
+               .name   = "system",
+               .offset = 0,
+               .size   = 64 * 1024 * 1024,
+       },
+       {
+               .name   = "userdata",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = 128 * 1024 * 1024,
+       },
+       {
+               .name   = "cache",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = 64 * 1024 * 1024,
+       },
+};
+
+static struct resource nand_flash_resources[] = {
+       [0] = {
+               .start  = 0xe6a30000,
+               .end    = 0xe6a3009b,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct sh_flctl_platform_data nand_flash_data = {
+       .parts          = nand_partition_info,
+       .nr_parts       = ARRAY_SIZE(nand_partition_info),
+       .flcmncr_val    = QTSEL_E | FCKSEL_E | TYPESEL_SET | NANWF_E
+                       | SHBUSSEL | SEL_16BIT,
+};
+
+static struct platform_device nand_flash_device = {
+       .name           = "sh_flctl",
+       .resource       = nand_flash_resources,
+       .num_resources  = ARRAY_SIZE(nand_flash_resources),
+       .dev            = {
+               .platform_data = &nand_flash_data,
+       },
+};
+
 static struct platform_device *g3evm_devices[] __initdata = {
        &nor_flash_device,
        &usb_host_device,
+       &keysc_device,
+       &nand_flash_device,
 };
 
 static struct map_desc g3evm_io_desc[] __initdata = {
@@ -196,6 +280,44 @@ static void __init g3evm_init(void)
        __raw_writew(0x6010, 0xe60581c6);       /* CGPOSR */
        __raw_writew(0x8a0a, 0xe605810c);       /* USBCR2 */
 
+       /* KEYSC @ CN7 */
+       gpio_request(GPIO_FN_PORT42_KEYOUT0, NULL);
+       gpio_request(GPIO_FN_PORT43_KEYOUT1, NULL);
+       gpio_request(GPIO_FN_PORT44_KEYOUT2, NULL);
+       gpio_request(GPIO_FN_PORT45_KEYOUT3, NULL);
+       gpio_request(GPIO_FN_PORT46_KEYOUT4, NULL);
+       gpio_request(GPIO_FN_PORT47_KEYOUT5, NULL);
+       gpio_request(GPIO_FN_PORT48_KEYIN0_PU, NULL);
+       gpio_request(GPIO_FN_PORT49_KEYIN1_PU, NULL);
+       gpio_request(GPIO_FN_PORT50_KEYIN2_PU, NULL);
+       gpio_request(GPIO_FN_PORT55_KEYIN3_PU, NULL);
+       gpio_request(GPIO_FN_PORT56_KEYIN4_PU, NULL);
+       gpio_request(GPIO_FN_PORT57_KEYIN5_PU, NULL);
+       gpio_request(GPIO_FN_PORT58_KEYIN6_PU, NULL);
+
+       /* FLCTL */
+       gpio_request(GPIO_FN_FCE0, NULL);
+       gpio_request(GPIO_FN_D0_ED0_NAF0, NULL);
+       gpio_request(GPIO_FN_D1_ED1_NAF1, NULL);
+       gpio_request(GPIO_FN_D2_ED2_NAF2, NULL);
+       gpio_request(GPIO_FN_D3_ED3_NAF3, NULL);
+       gpio_request(GPIO_FN_D4_ED4_NAF4, NULL);
+       gpio_request(GPIO_FN_D5_ED5_NAF5, NULL);
+       gpio_request(GPIO_FN_D6_ED6_NAF6, NULL);
+       gpio_request(GPIO_FN_D7_ED7_NAF7, NULL);
+       gpio_request(GPIO_FN_D8_ED8_NAF8, NULL);
+       gpio_request(GPIO_FN_D9_ED9_NAF9, NULL);
+       gpio_request(GPIO_FN_D10_ED10_NAF10, NULL);
+       gpio_request(GPIO_FN_D11_ED11_NAF11, NULL);
+       gpio_request(GPIO_FN_D12_ED12_NAF12, NULL);
+       gpio_request(GPIO_FN_D13_ED13_NAF13, NULL);
+       gpio_request(GPIO_FN_D14_ED14_NAF14, NULL);
+       gpio_request(GPIO_FN_D15_ED15_NAF15, NULL);
+       gpio_request(GPIO_FN_WE0_XWR0_FWE, NULL);
+       gpio_request(GPIO_FN_FRB, NULL);
+       /* FOE, FCDE, FSC on dedicated pins */
+       __raw_writel(__raw_readl(0xe6158048) & ~(1 << 15), 0xe6158048);
+
        sh7367_add_standard_devices();
 
        platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices));
index 5acd623..10673a9 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/io.h>
+#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
 #include <linux/gpio.h>
 #include <mach/sh7377.h>
 #include <mach/common.h>
@@ -128,9 +130,49 @@ static struct platform_device usb_host_device = {
        .resource       = usb_host_resources,
 };
 
+/* KEYSC */
+static struct sh_keysc_info keysc_info = {
+       .mode           = SH_KEYSC_MODE_5,
+       .scan_timing    = 3,
+       .delay          = 100,
+       .keycodes = {
+               KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,
+               KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
+               KEY_M, KEY_N, KEY_U, KEY_P, KEY_Q, KEY_R,
+               KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X,
+               KEY_Y, KEY_Z, KEY_HOME, KEY_SLEEP, KEY_WAKEUP, KEY_COFFEE,
+               KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5,
+               KEY_6, KEY_7, KEY_8, KEY_9, KEY_STOP, KEY_COMPUTER,
+       },
+};
+
+static struct resource keysc_resources[] = {
+       [0] = {
+               .name   = "KEYSC",
+               .start  = 0xe61b0000,
+               .end    = 0xe61b000f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 79,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device keysc_device = {
+       .name           = "sh_keysc",
+       .id             = 0, /* keysc0 clock */
+       .num_resources  = ARRAY_SIZE(keysc_resources),
+       .resource       = keysc_resources,
+       .dev    = {
+               .platform_data  = &keysc_info,
+       },
+};
+
 static struct platform_device *g4evm_devices[] __initdata = {
        &nor_flash_device,
        &usb_host_device,
+       &keysc_device,
 };
 
 static struct map_desc g4evm_io_desc[] __initdata = {
@@ -196,6 +238,21 @@ static void __init g4evm_init(void)
        __raw_writew(0x6010, 0xe60581c6);       /* CGPOSR */
        __raw_writew(0x8a0a, 0xe605810c);       /* USBCR2 */
 
+       /* KEYSC @ CN31 */
+       gpio_request(GPIO_FN_PORT60_KEYOUT5, NULL);
+       gpio_request(GPIO_FN_PORT61_KEYOUT4, NULL);
+       gpio_request(GPIO_FN_PORT62_KEYOUT3, NULL);
+       gpio_request(GPIO_FN_PORT63_KEYOUT2, NULL);
+       gpio_request(GPIO_FN_PORT64_KEYOUT1, NULL);
+       gpio_request(GPIO_FN_PORT65_KEYOUT0, NULL);
+       gpio_request(GPIO_FN_PORT66_KEYIN0_PU, NULL);
+       gpio_request(GPIO_FN_PORT67_KEYIN1_PU, NULL);
+       gpio_request(GPIO_FN_PORT68_KEYIN2_PU, NULL);
+       gpio_request(GPIO_FN_PORT69_KEYIN3_PU, NULL);
+       gpio_request(GPIO_FN_PORT70_KEYIN4_PU, NULL);
+       gpio_request(GPIO_FN_PORT71_KEYIN5_PU, NULL);
+       gpio_request(GPIO_FN_PORT72_KEYIN6_PU, NULL);
+
        sh7377_add_standard_devices();
 
        platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices));
index 58bd54e..bb940c6 100644 (file)
@@ -75,6 +75,11 @@ static struct clk usb0_clk = {
        .name       = "usb0",
 };
 
+/* a static keysc0 clk for now - enough to get sh_keysc working */
+static struct clk keysc0_clk = {
+       .name       = "keysc0",
+};
+
 static struct clk_lookup lookups[] = {
        {
                .clk = &peripheral_clk,
@@ -82,6 +87,8 @@ static struct clk_lookup lookups[] = {
                .clk = &r_clk,
        }, {
                .clk = &usb0_clk,
+       }, {
+               .clk = &keysc0_clk,
        }
 };
 
index 6a547b4..5ff70ca 100644 (file)
@@ -27,6 +27,8 @@
 
 enum {
        UNUSED_INTCA = 0,
+       ENABLED,
+       DISABLED,
 
        /* interrupt sources INTCA */
        IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -46,8 +48,8 @@ enum {
        MSIOF2, MSIOF1,
        SCIFA4, SCIFA5, SCIFB,
        FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
-       SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
-       SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2, SDHI1_SDHI1I3,
+       SDHI0,
+       SDHI1,
        MSU_MSU, MSU_MSU2,
        IREM,
        SIU,
@@ -59,7 +61,7 @@ enum {
        TTI20,
        MISTY,
        DDM,
-       SDHI2_SDHI2I0, SDHI2_SDHI2I1, SDHI2_SDHI2I2, SDHI2_SDHI2I3,
+       SDHI2,
        RWDT0, RWDT1,
        DMAC_1_DEI0, DMAC_1_DEI1, DMAC_1_DEI2, DMAC_1_DEI3,
        DMAC_2_DEI4, DMAC_2_DEI5, DMAC_2_DADERR,
@@ -70,7 +72,7 @@ enum {
 
        /* interrupt groups INTCA */
        DMAC_1, DMAC_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2,
-       ETM11, ARM11, USBHS, FLCTL, IIC1, SDHI0, SDHI1, SDHI2,
+       ETM11, ARM11, USBHS, FLCTL, IIC1
 };
 
 static struct intc_vect intca_vectors[] = {
@@ -105,10 +107,10 @@ static struct intc_vect intca_vectors[] = {
        INTC_VECT(SCIFB, 0x0d60),
        INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
        INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
-       INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
-       INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
-       INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
-       INTC_VECT(SDHI1_SDHI1I2, 0x0ec0), INTC_VECT(SDHI1_SDHI1I3, 0x0ee0),
+       INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
+       INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
+       INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
+       INTC_VECT(SDHI1, 0x0ec0), INTC_VECT(SDHI1, 0x0ee0),
        INTC_VECT(MSU_MSU, 0x0f20), INTC_VECT(MSU_MSU2, 0x0f40),
        INTC_VECT(IREM, 0x0f60),
        INTC_VECT(SIU, 0x0fa0),
@@ -122,8 +124,8 @@ static struct intc_vect intca_vectors[] = {
        INTC_VECT(TTI20, 0x1100),
        INTC_VECT(MISTY, 0x1120),
        INTC_VECT(DDM, 0x1140),
-       INTC_VECT(SDHI2_SDHI2I0, 0x1200), INTC_VECT(SDHI2_SDHI2I1, 0x1220),
-       INTC_VECT(SDHI2_SDHI2I2, 0x1240), INTC_VECT(SDHI2_SDHI2I3, 0x1260),
+       INTC_VECT(SDHI2, 0x1200), INTC_VECT(SDHI2, 0x1220),
+       INTC_VECT(SDHI2, 0x1240), INTC_VECT(SDHI2, 0x1260),
        INTC_VECT(RWDT0, 0x1280), INTC_VECT(RWDT1, 0x12a0),
        INTC_VECT(DMAC_1_DEI0, 0x2000), INTC_VECT(DMAC_1_DEI1, 0x2020),
        INTC_VECT(DMAC_1_DEI2, 0x2040), INTC_VECT(DMAC_1_DEI3, 0x2060),
@@ -158,12 +160,6 @@ static struct intc_group intca_groups[] __initdata = {
        INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
                   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
        INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
-       INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
-                  SDHI0_SDHI0I2, SDHI0_SDHI0I3),
-       INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
-                  SDHI1_SDHI1I2, SDHI1_SDHI1I3),
-       INTC_GROUP(SDHI2, SDHI2_SDHI2I0, SDHI2_SDHI2I1,
-                  SDHI2_SDHI2I2, SDHI2_SDHI2I3),
 };
 
 static struct intc_mask_reg intca_mask_registers[] = {
@@ -193,10 +189,10 @@ static struct intc_mask_reg intca_mask_registers[] = {
          { SCIFB, SCIFA5, SCIFA4, MSIOF1,
            0, 0, MSIOF2, 0 } },
        { 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
-         { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
        { 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
-         { SDHI1_SDHI1I3, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            TTI20, USBDMAC_USHDMI, SPU, SIU } },
        { 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
          { CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -211,7 +207,7 @@ static struct intc_mask_reg intca_mask_registers[] = {
          { 0, 0, TPU0, TPU1,
            TPU2, TPU3, TPU4, 0 } },
        { 0xe69400b4, 0xe69400f4, 8, /* IMR13A / IMCR13A */
-         { SDHI2_SDHI2I3, SDHI2_SDHI2I2, SDHI2_SDHI2I1, SDHI2_SDHI2I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            MISTY, CMT3, RWDT1, RWDT0 } },
 };
 
@@ -258,10 +254,14 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
          { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } },
 };
 
-static DECLARE_INTC_DESC_ACK(intca_desc, "sh7367-intca",
-                            intca_vectors, intca_groups,
-                            intca_mask_registers, intca_prio_registers,
-                            intca_sense_registers, intca_ack_registers);
+static struct intc_desc intca_desc __initdata = {
+       .name = "sh7367-intca",
+       .force_enable = ENABLED,
+       .force_disable = DISABLED,
+       .hw = INTC_HW_DESC(intca_vectors, intca_groups,
+                          intca_mask_registers, intca_prio_registers,
+                          intca_sense_registers, intca_ack_registers),
+};
 
 void __init sh7367_init_irq(void)
 {
index c57a923..3ce9d9b 100644 (file)
@@ -27,6 +27,8 @@
 
 enum {
        UNUSED_INTCA = 0,
+       ENABLED,
+       DISABLED,
 
        /* interrupt sources INTCA */
        IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -47,14 +49,14 @@ enum {
        MSIOF2, MSIOF1,
        SCIFA4, SCIFA5, SCIFB,
        FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
-       SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
-       SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2,
+       SDHI0,
+       SDHI1,
        IRREM,
        IRDA,
        TPU0,
        TTI20,
        DDM,
-       SDHI2_SDHI2I0, SDHI2_SDHI2I1, SDHI2_SDHI2I2, SDHI2_SDHI2I3,
+       SDHI2,
        RWDT0,
        DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
        DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
@@ -82,7 +84,7 @@ enum {
 
        /* interrupt groups INTCA */
        DMAC1_1, DMAC1_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2, SHWYSTAT,
-       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1, SDHI0, SDHI1, SDHI2
+       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1
 };
 
 static struct intc_vect intca_vectors[] __initdata = {
@@ -123,17 +125,17 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(SCIFB, 0x0d60),
        INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
        INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
-       INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
-       INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
-       INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
-       INTC_VECT(SDHI1_SDHI1I2, 0x0ec0),
+       INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
+       INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
+       INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
+       INTC_VECT(SDHI1, 0x0ec0),
        INTC_VECT(IRREM, 0x0f60),
        INTC_VECT(IRDA, 0x0480),
        INTC_VECT(TPU0, 0x04a0),
        INTC_VECT(TTI20, 0x1100),
        INTC_VECT(DDM, 0x1140),
-       INTC_VECT(SDHI2_SDHI2I0, 0x1200), INTC_VECT(SDHI2_SDHI2I1, 0x1220),
-       INTC_VECT(SDHI2_SDHI2I2, 0x1240), INTC_VECT(SDHI2_SDHI2I3, 0x1260),
+       INTC_VECT(SDHI2, 0x1200), INTC_VECT(SDHI2, 0x1220),
+       INTC_VECT(SDHI2, 0x1240), INTC_VECT(SDHI2, 0x1260),
        INTC_VECT(RWDT0, 0x1280),
        INTC_VECT(DMAC1_1_DEI0, 0x2000), INTC_VECT(DMAC1_1_DEI1, 0x2020),
        INTC_VECT(DMAC1_1_DEI2, 0x2040), INTC_VECT(DMAC1_1_DEI3, 0x2060),
@@ -193,12 +195,6 @@ static struct intc_group intca_groups[] __initdata = {
        INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
                   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
        INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
-       INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
-                  SDHI0_SDHI0I2, SDHI0_SDHI0I3),
-       INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
-                  SDHI1_SDHI1I2),
-       INTC_GROUP(SDHI2, SDHI2_SDHI2I0, SDHI2_SDHI2I1,
-                  SDHI2_SDHI2I2, SDHI2_SDHI2I3),
        INTC_GROUP(SHWYSTAT, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
 };
 
@@ -234,10 +230,10 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { SCIFB, SCIFA5, SCIFA4, MSIOF1,
            0, 0, MSIOF2, 0 } },
        { 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
-         { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
        { 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
-         { 0, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
+         { 0, DISABLED, ENABLED, ENABLED,
            TTI20, USBHSDMAC0_USHDMI, 0, 0 } },
        { 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
          { CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -252,7 +248,7 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { 0, 0, TPU0, 0,
            0, 0, 0, 0 } },
        { 0xe69400b4, 0xe69400f4, 8, /* IMR13A / IMCR13A */
-         { SDHI2_SDHI2I3, SDHI2_SDHI2I2, SDHI2_SDHI2I1, SDHI2_SDHI2I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            0, CMT3, 0, RWDT0 } },
        { 0xe6950080, 0xe69500c0, 8, /* IMR0A3 / IMCR0A3 */
          { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
@@ -358,10 +354,14 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
          { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } },
 };
 
-static DECLARE_INTC_DESC_ACK(intca_desc, "sh7372-intca",
-                            intca_vectors, intca_groups,
-                            intca_mask_registers, intca_prio_registers,
-                            intca_sense_registers, intca_ack_registers);
+static struct intc_desc intca_desc __initdata = {
+       .name = "sh7372-intca",
+       .force_enable = ENABLED,
+       .force_disable = DISABLED,
+       .hw = INTC_HW_DESC(intca_vectors, intca_groups,
+                          intca_mask_registers, intca_prio_registers,
+                          intca_sense_registers, intca_ack_registers),
+};
 
 void __init sh7372_init_irq(void)
 {
index 125021c..5c781e2 100644 (file)
@@ -27,6 +27,8 @@
 
 enum {
        UNUSED_INTCA = 0,
+       ENABLED,
+       DISABLED,
 
        /* interrupt sources INTCA */
        IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -49,8 +51,8 @@ enum {
        MSIOF2, MSIOF1,
        SCIFA4, SCIFA5, SCIFB,
        FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
-       SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
-       SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2, SDHI1_SDHI1I3,
+       SDHI0,
+       SDHI1,
        MSU_MSU, MSU_MSU2,
        IRREM,
        MSUG,
@@ -84,7 +86,7 @@ enum {
 
        /* interrupt groups INTCA */
        DMAC_1, DMAC_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2, SHWYSTAT,
-       AP_ARM1, AP_ARM2, USBHS, SPU2, FLCTL, IIC1, SDHI0, SDHI1,
+       AP_ARM1, AP_ARM2, USBHS, SPU2, FLCTL, IIC1,
        ICUSB, ICUDMC
 };
 
@@ -128,10 +130,10 @@ static struct intc_vect intca_vectors[] = {
        INTC_VECT(SCIFB, 0x0d60),
        INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
        INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
-       INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
-       INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
-       INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
-       INTC_VECT(SDHI1_SDHI1I2, 0x0ec0), INTC_VECT(SDHI1_SDHI1I3, 0x0ee0),
+       INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
+       INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
+       INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
+       INTC_VECT(SDHI1, 0x0ec0), INTC_VECT(SDHI1, 0x0ee0),
        INTC_VECT(MSU_MSU, 0x0f20), INTC_VECT(MSU_MSU2, 0x0f40),
        INTC_VECT(IRREM, 0x0f60),
        INTC_VECT(MSUG, 0x0fa0),
@@ -195,10 +197,6 @@ static struct intc_group intca_groups[] __initdata = {
        INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
                   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
        INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
-       INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
-                  SDHI0_SDHI0I2, SDHI0_SDHI0I3),
-       INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
-                  SDHI1_SDHI1I2, SDHI1_SDHI1I3),
        INTC_GROUP(SHWYSTAT, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
        INTC_GROUP(ICUSB, ICUSB_ICUSB0, ICUSB_ICUSB1),
        INTC_GROUP(ICUDMC, ICUDMC_ICUDMC1, ICUDMC_ICUDMC2),
@@ -236,10 +234,10 @@ static struct intc_mask_reg intca_mask_registers[] = {
          { SCIFB, SCIFA5, SCIFA4, MSIOF1,
            0, 0, MSIOF2, 0 } },
        { 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
-         { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
        { 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
-         { SDHI1_SDHI1I3, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
+         { DISABLED, DISABLED, ENABLED, ENABLED,
            TTI20, USBDMAC_USHDMI, 0, MSUG } },
        { 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
          { CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -339,10 +337,14 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
          { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } },
 };
 
-static DECLARE_INTC_DESC_ACK(intca_desc, "sh7377-intca",
-                            intca_vectors, intca_groups,
-                            intca_mask_registers, intca_prio_registers,
-                            intca_sense_registers, intca_ack_registers);
+static struct intc_desc intca_desc __initdata = {
+       .name = "sh7377-intca",
+       .force_enable = ENABLED,
+       .force_disable = DISABLED,
+       .hw = INTC_HW_DESC(intca_vectors, intca_groups,
+                          intca_mask_registers, intca_prio_registers,
+                          intca_sense_registers, intca_ack_registers),
+};
 
 void __init sh7377_init_irq(void)
 {
index 337199e..76a347b 100644 (file)
@@ -2140,18 +2140,18 @@ void omap2_gpio_resume_after_retention(void)
                if (gen) {
                        u32 old0, old1;
 
-                       if (cpu_is_omap24xx() || cpu_is_omap44xx()) {
+                       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
                                old0 = __raw_readl(bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT0);
                                old1 = __raw_readl(bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT1);
-                       __raw_writel(old0 | gen, bank->base +
+                               __raw_writel(old0 | gen, bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT0);
-                       __raw_writel(old1 | gen, bank->base +
+                               __raw_writel(old1 | gen, bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT1);
-                       __raw_writel(old0, bank->base +
+                               __raw_writel(old0, bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT0);
-                       __raw_writel(old1, bank->base +
+                               __raw_writel(old1, bank->base +
                                        OMAP24XX_GPIO_LEVELDETECT1);
                        }
 
index 8d160f1..56e7f2e 100644 (file)
@@ -6,7 +6,7 @@ struct blizzard_platform_data {
        void            (*power_down)(struct device *dev);
        unsigned long   (*get_clock_rate)(struct device *dev);
 
-       unsigned        te_connected : 1;
+       unsigned        te_connected:1;
 };
 
 #endif
index ed8786c..7514174 100644 (file)
@@ -167,10 +167,14 @@ IS_OMAP_SUBCLASS(443x, 0x443)
 #if defined(MULTI_OMAP2)
 # if defined(CONFIG_ARCH_OMAP2)
 #  undef  cpu_is_omap24xx
-#  undef  cpu_is_omap242x
-#  undef  cpu_is_omap243x
 #  define cpu_is_omap24xx()            is_omap24xx()
+# endif
+# if defined (CONFIG_ARCH_OMAP2420)
+#  undef  cpu_is_omap242x
 #  define cpu_is_omap242x()            is_omap242x()
+# endif
+# if defined (CONFIG_ARCH_OMAP2430)
+#  undef  cpu_is_omap243x
 #  define cpu_is_omap243x()            is_omap243x()
 # endif
 # if defined(CONFIG_ARCH_OMAP3)
index d6a0e27..9fbd914 100644 (file)
@@ -24,7 +24,7 @@
 #define __ASM_ARM_ARCH_OMAP_PRCM_H
 
 u32 omap_prcm_get_reset_sources(void);
-void omap_prcm_arch_reset(char mode);
+void omap_prcm_arch_reset(char mode, const char *cmd);
 int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, u8 idlest,
                         const char *name);
 
index c58a4ef..d0a119f 100644 (file)
@@ -22,7 +22,7 @@ static inline void arch_idle(void)
        cpu_do_idle();
 }
 
-static inline void omap1_arch_reset(char mode)
+static inline void omap1_arch_reset(char mode, const char *cmd)
 {
        /*
         * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
@@ -43,9 +43,9 @@ static inline void omap1_arch_reset(char mode)
 static inline void arch_reset(char mode, const char *cmd)
 {
        if (!cpu_class_is_omap2())
-               omap1_arch_reset(mode);
+               omap1_arch_reset(mode, cmd);
        else
-               omap_prcm_arch_reset(mode);
+               omap_prcm_arch_reset(mode, cmd);
 }
 
 #endif
index 288e29e..568578d 100644 (file)
@@ -53,7 +53,7 @@ enum musb_interface    {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
 
 extern void usb_musb_init(struct omap_musb_board_data *board_data);
 
-extern void usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata);
+extern void usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata);
 
 #endif
 
index e47686e..52dfcc8 100644 (file)
@@ -133,8 +133,7 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
                dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
                        irqst_spcr2);
                /* Writing zero to XSYNC_ERR clears the IRQ */
-               MCBSP_WRITE(mcbsp_tx, SPCR2,
-                           MCBSP_READ_CACHE(mcbsp_tx, SPCR2) & ~(XSYNC_ERR));
+               MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
        } else {
                complete(&mcbsp_tx->tx_irq_completion);
        }
@@ -154,8 +153,7 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
                dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
                        irqst_spcr1);
                /* Writing zero to RSYNC_ERR clears the IRQ */
-               MCBSP_WRITE(mcbsp_rx, SPCR1,
-                           MCBSP_READ_CACHE(mcbsp_rx, SPCR1) & ~(RSYNC_ERR));
+               MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
        } else {
                complete(&mcbsp_rx->tx_irq_completion);
        }
@@ -934,8 +932,7 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
        /* if frame sync error - clear the error */
        if (MCBSP_READ(mcbsp, SPCR2) & XSYNC_ERR) {
                /* clear error */
-               MCBSP_WRITE(mcbsp, SPCR2,
-                               MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XSYNC_ERR));
+               MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
                /* resend */
                return -1;
        } else {
@@ -975,8 +972,7 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf)
        /* if frame sync error - clear the error */
        if (MCBSP_READ(mcbsp, SPCR1) & RSYNC_ERR) {
                /* clear error */
-               MCBSP_WRITE(mcbsp, SPCR1,
-                               MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RSYNC_ERR));
+               MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
                /* resend */
                return -1;
        } else {
index e87ce8f..7d6ed72 100644 (file)
@@ -140,8 +140,6 @@ static void arch_decomp_error(const char *x)
 #define arch_error arch_decomp_error
 #endif
 
-static void error(char *err);
-
 #ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
 static inline void arch_enable_uart_fifo(void)
 {
index ef019f2..f2d1139 100644 (file)
@@ -379,6 +379,39 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct pwm_device *pwm = platform_get_drvdata(pdev);
+
+       /* No one preserve these values during suspend so reset them
+        * Otherwise driver leaves PWM unconfigured if same values
+        * passed to pwm_config
+        */
+       pwm->period_ns = 0;
+       pwm->duty_ns = 0;
+
+       return 0;
+}
+
+static int s3c_pwm_resume(struct platform_device *pdev)
+{
+       struct pwm_device *pwm = platform_get_drvdata(pdev);
+       unsigned long tcon;
+
+       /* Restore invertion */
+       tcon = __raw_readl(S3C2410_TCON);
+       tcon |= pwm_tcon_invert(pwm);
+       __raw_writel(tcon, S3C2410_TCON);
+
+       return 0;
+}
+
+#else
+#define s3c_pwm_suspend NULL
+#define s3c_pwm_resume NULL
+#endif
+
 static struct platform_driver s3c_pwm_driver = {
        .driver         = {
                .name   = "s3c24xx-pwm",
@@ -386,6 +419,8 @@ static struct platform_driver s3c_pwm_driver = {
        },
        .probe          = s3c_pwm_probe,
        .remove         = __devexit_p(s3c_pwm_remove),
+       .suspend        = s3c_pwm_suspend,
+       .resume         = s3c_pwm_resume,
 };
 
 static int __init pwm_init(void)
index 53c1e1d..c078849 100644 (file)
@@ -23,12 +23,15 @@ config RWSEM_XCHGADD_ALGORITHM
 
 config BLACKFIN
        def_bool y
+       select HAVE_ARCH_KGDB
+       select HAVE_ARCH_TRACEHOOK
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_IDE
-       select HAVE_KERNEL_GZIP
-       select HAVE_KERNEL_BZIP2
-       select HAVE_KERNEL_LZMA
+       select HAVE_KERNEL_GZIP if RAMKERNEL
+       select HAVE_KERNEL_BZIP2 if RAMKERNEL
+       select HAVE_KERNEL_LZMA if RAMKERNEL
        select HAVE_OPROFILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
 
@@ -45,9 +48,6 @@ config ZONE_DMA
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
-config GENERIC_HWEIGHT
-       def_bool y
-
 config GENERIC_HARDIRQS
        def_bool y
 
@@ -239,7 +239,7 @@ endchoice
 
 config SMP
        depends on BF561
-       select GENERIC_CLOCKEVENTS
+       select TICKSOURCE_CORETMR
        bool "Symmetric multi-processing support"
        ---help---
          This enables support for systems with more than one CPU,
@@ -253,11 +253,20 @@ config NR_CPUS
        depends on SMP
        default 2 if BF561
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SMP && HOTPLUG
+       default y
+
 config IRQ_PER_CPU
        bool
        depends on SMP
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y
+       depends on SMP
+
 config BF_REV_MIN
        int
        default 0 if (BF51x || BF52x || (BF54x && !BF54xM))
@@ -349,7 +358,7 @@ config MEM_MT48LC8M32B2B5_7
 
 config MEM_MT48LC32M16A2TG_75
        bool
-       depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP)
+       depends on (BFIN527_EZKIT || BFIN527_EZKIT_V2 || BFIN532_IP0X || BLACKSTAMP)
        default y
 
 config MEM_MT48LC32M8A2_75
@@ -401,10 +410,18 @@ config BOOT_LOAD
 config ROM_BASE
        hex "Kernel ROM Base"
        depends on ROMKERNEL
-       default "0x20040000"
+       default "0x20040040"
        range 0x20000000 0x20400000 if !(BF54x || BF561)
        range 0x20000000 0x30000000 if (BF54x || BF561)
        help
+         Make sure your ROM base does not include any file-header
+         information that is prepended to the kernel.
+
+         For example, the bootable U-Boot format (created with
+         mkimage) has a 64 byte header (0x40).  So while the image
+         you write to flash might start at say 0x20080000, you have
+         to add 0x40 to get the kernel's ROM base as it will come
+         after the header.
 
 comment "Clock/PLL Setup"
 
@@ -448,7 +465,7 @@ config VCO_MULT
        range 1 64
        default "22" if BFIN533_EZKIT
        default "45" if BFIN533_STAMP
-       default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT || BFIN548_BLUETECHNIX_CM || BFIN538_EZKIT)
+       default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN527_EZKIT_V2 || BFIN548_EZKIT || BFIN548_BLUETECHNIX_CM || BFIN538_EZKIT)
        default "22" if BFIN533_BLUETECHNIX_CM
        default "20" if (BFIN537_BLUETECHNIX_CM_E || BFIN537_BLUETECHNIX_CM_U || BFIN527_BLUETECHNIX_CM || BFIN561_BLUETECHNIX_CM)
        default "20" if BFIN561_EZKIT
@@ -609,23 +626,23 @@ config GENERIC_CLOCKEVENTS
        bool "Generic clock events"
        default y
 
-choice
-       prompt "Kernel Tick Source"
+menu "Clock event device"
        depends on GENERIC_CLOCKEVENTS
-       default TICKSOURCE_CORETMR
-
 config TICKSOURCE_GPTMR0
-       bool "Gptimer0 (SCLK domain)"
+       bool "GPTimer0"
+       depends on !SMP
        select BFIN_GPTIMERS
 
 config TICKSOURCE_CORETMR
-       bool "Core timer (CCLK domain)"
-
-endchoice
+       bool "Core timer"
+       default y
+endmenu
 
-config CYCLES_CLOCKSOURCE
-       bool "Use 'CYCLES' as a clocksource"
+menu "Clock souce"
        depends on GENERIC_CLOCKEVENTS
+config CYCLES_CLOCKSOURCE
+       bool "CYCLES"
+       default y
        depends on !BFIN_SCRATCH_REG_CYCLES
        depends on !SMP
        help
@@ -636,10 +653,10 @@ config CYCLES_CLOCKSOURCE
          writing the registers will most likely crash the kernel.
 
 config GPTMR0_CLOCKSOURCE
-       bool "Use GPTimer0 as a clocksource"
+       bool "GPTimer0"
        select BFIN_GPTIMERS
-       depends on GENERIC_CLOCKEVENTS
        depends on !TICKSOURCE_GPTMR0
+endmenu
 
 config ARCH_USES_GETTIMEOFFSET
        depends on !GENERIC_CLOCKEVENTS
@@ -1116,24 +1133,6 @@ config PCI
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-       bool "Support for hot-pluggable device"
-         help
-         Say Y here if you want to plug devices into your computer while
-         the system is running, and be able to use them quickly.  In many
-         cases, the devices can likewise be unplugged at any time too.
-
-         One well known example of this is PCMCIA- or PC-cards, credit-card
-         size devices such as network cards, modems or hard drives which are
-         plugged into slots found on all modern laptop computers.  Another
-         example, used on modern desktops as well as laptops, is USB.
-
-         Enable HOTPLUG and build a modular kernel.  Get agent software
-         (from <http://linux-hotplug.sourceforge.net/>) and install it.
-         Then your kernel will automatically call out to a user mode "policy
-         agent" (/sbin/hotplug) to load modules and set up software needed
-         to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
@@ -1147,7 +1146,6 @@ source "fs/Kconfig.binfmt"
 endmenu
 
 menu "Power management options"
-       depends on !SMP
 
 source "kernel/power/Kconfig"
 
@@ -1240,7 +1238,6 @@ config PM_BFIN_WAKE_GP
 endmenu
 
 menu "CPU Frequency scaling"
-       depends on !SMP
 
 source "drivers/cpufreq/Kconfig"
 
index 87f195e..aec89a5 100644 (file)
@@ -18,9 +18,6 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
-config HAVE_ARCH_KGDB
-       def_bool y
-
 config DEBUG_VERBOSE
        bool "Verbose fault messages"
        default y
@@ -238,6 +235,15 @@ config EARLY_PRINTK
          all of this lives in the init section and is thrown away after the
          kernel boots completely.
 
+config NMI_WATCHDOG
+       bool "Enable NMI watchdog to help debugging lockup on SMP"
+       default n
+       depends on (SMP && !BFIN_SCRATCH_REG_RETN)
+       help
+         If any CPU in the system does not execute the period local timer
+         interrupt for more than 5 seconds, then the NMI handler dumps debug
+         information. This information can be used to debug the lockup.
+
 config CPLB_INFO
        bool "Display the CPLB information"
        help
index d4c7177..5a97a31 100644 (file)
@@ -14,6 +14,9 @@ OBJCOPYFLAGS     := -O binary -R .note -R .comment -S
 GZFLAGS          := -9
 
 KBUILD_CFLAGS           += $(call cc-option,-mno-fdpic)
+ifeq ($(CONFIG_ROMKERNEL),y)
+KBUILD_CFLAGS           += -mlong-calls
+endif
 KBUILD_AFLAGS           += $(call cc-option,-mno-fdpic)
 CFLAGS_MODULE    += -mlong-calls
 LDFLAGS_MODULE   += -m elf32bfin
@@ -130,7 +133,6 @@ KBUILD_CFLAGS += -Iarch/$(ARCH)/mach-$(MACHINE)/include
 KBUILD_CPPFLAGS        += $(patsubst %,-I$(srctree)/%include,$(machdirs))
 
 CLEAN_FILES += \
-       arch/$(ARCH)/include/asm/asm-offsets.h \
        arch/$(ARCH)/kernel/asm-offsets.s \
 
 archclean:
@@ -138,7 +140,7 @@ archclean:
 
 INSTALL_PATH ?= /tftpboot
 boot := arch/$(ARCH)/boot
-BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma
+BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip
 PHONY += $(BOOT_TARGETS) install
 KBUILD_IMAGE := $(boot)/vmImage
 
@@ -156,6 +158,7 @@ define archhelp
   echo  '  vmImage.bz2     - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)'
   echo  '* vmImage.gz      - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)'
   echo  '  vmImage.lzma    - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)'
+  echo  '  vmImage.xip     - XIP Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.xip)'
   echo  '  install         - Install kernel using'
   echo  '                     (your) ~/bin/$(INSTALLKERNEL) or'
   echo  '                     (distribution) PATH: $(INSTALLKERNEL) or'
index e9c48c6..d1b3d60 100644 (file)
@@ -8,14 +8,18 @@
 
 MKIMAGE := $(srctree)/scripts/mkuboot.sh
 
-targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma
-extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
+targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xip
+
+UIMAGE_OPTS-y :=
+UIMAGE_OPTS-$(CONFIG_RAMKERNEL) += -a $(CONFIG_BOOT_LOAD)
+UIMAGE_OPTS-$(CONFIG_ROMKERNEL) += -a $(CONFIG_ROM_BASE) -x
 
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
-                   -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
+                   -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' \
                    -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \
-                   -d $< $@
+                   $(UIMAGE_OPTS-y) -d $< $@
 
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
@@ -29,6 +33,12 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
 $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
        $(call if_changed,lzma)
 
+# The mkimage tool wants 64bytes prepended to the image
+quiet_cmd_mk_bin_xip = BIN     $@
+      cmd_mk_bin_xip = ( printf '%64s' | tr ' ' '\377' ; cat $< ) > $@
+$(obj)/vmlinux.bin.xip: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,mk_bin_xip)
+
 $(obj)/vmImage.bin: $(obj)/vmlinux.bin
        $(call if_changed,uimage,none)
 
@@ -41,10 +51,15 @@ $(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz
 $(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma
        $(call if_changed,uimage,lzma)
 
+$(obj)/vmImage.xip: $(obj)/vmlinux.bin.xip
+       $(call if_changed,uimage,none)
+
 suffix-y                      := bin
 suffix-$(CONFIG_KERNEL_GZIP)  := gz
 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
 suffix-$(CONFIG_KERNEL_LZMA)  := lzma
+suffix-$(CONFIG_ROMKERNEL)    := xip
+
 $(obj)/vmImage: $(obj)/vmImage.$(suffix-y)
        @ln -sf $(notdir $<) $@
 
index e315594..cf7c9bc 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_DEFAULT_CFQ is not set
 CONFIG_DEFAULT_NOOP=y
 CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_BF518=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
@@ -154,8 +182,8 @@ CONFIG_BF_REV_0_0=y
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
-CONFIG_BF51x=y
 CONFIG_MEM_MT48LC32M8A2_75=y
+CONFIG_BF51x=y
 CONFIG_BFIN518F_EZBRD=y
 
 #
@@ -313,7 +341,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -322,16 +349,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -342,7 +371,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -398,11 +427,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -426,7 +450,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -437,6 +460,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -450,7 +474,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -461,13 +488,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -488,6 +510,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -545,6 +568,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -560,6 +584,11 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -576,10 +605,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -614,6 +653,9 @@ CONFIG_PHYLIB=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -622,10 +664,14 @@ CONFIG_BFIN_MAC=y
 CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_BFIN_MAC_RMII is not set
+CONFIG_BFIN_MAC_USE_HWSTAMP=y
 # CONFIG_SMC91X is not set
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -634,15 +680,16 @@ CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -677,7 +724,10 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -688,16 +738,13 @@ CONFIG_INPUT_MISC=y
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
@@ -715,6 +762,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -726,12 +774,10 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -739,6 +785,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -771,14 +818,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -795,13 +834,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_SPI_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -817,6 +861,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -827,11 +872,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -853,28 +902,20 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -912,10 +953,11 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
 CONFIG_SDH_BFIN=m
 CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND=y
-# CONFIG_SDH_BFIN_ENABLE_SDIO_IRQ is not set
-# CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
 # CONFIG_ACCESSIBILITY is not set
@@ -950,6 +992,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -961,6 +1004,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -981,10 +1025,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=m
@@ -994,9 +1049,13 @@ CONFIG_EXT2_FS=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1006,6 +1065,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1027,13 +1091,9 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1042,8 +1102,8 @@ CONFIG_SYSFS=y
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS2_FS is not set
-# CONFIG_YAFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1062,7 +1122,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1127,14 +1186,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1142,31 +1206,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1191,6 +1263,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1199,14 +1272,14 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1238,11 +1311,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1279,6 +1354,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1286,11 +1362,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1299,6 +1377,8 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 075e0fd..31c2a6d 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_IOSCHED_NOOP=y
 # CONFIG_DEFAULT_CFQ is not set
 CONFIG_DEFAULT_NOOP=y
 CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_BF526=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
@@ -154,8 +182,7 @@ CONFIG_BF_REV_0_0=y
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
-CONFIG_BF52x=y
-CONFIG_MEM_MT48LC32M16A2TG_75=y
+CONFIG_MEM_MT48H32M16LFCJ_75=y
 CONFIG_IRQ_PLL_WAKEUP=7
 CONFIG_IRQ_DMA0_ERROR=7
 CONFIG_IRQ_DMAR0_BLK=7
@@ -200,7 +227,9 @@ CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
 CONFIG_IRQ_PORTF_INTA=13
 CONFIG_IRQ_PORTF_INTB=13
+CONFIG_BF52x=y
 # CONFIG_BFIN527_EZKIT is not set
+# CONFIG_BFIN527_EZKIT_V2 is not set
 # CONFIG_BFIN527_BLUETECHNIX_CM is not set
 CONFIG_BFIN526_EZBRD=y
 
@@ -318,7 +347,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -327,16 +355,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -347,6 +377,10 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
+# Asynchronous Memory Configuration
+#
+
+#
 # EBIU_AMGCTL Global Control
 #
 CONFIG_C_AMCKEN=y
@@ -399,11 +433,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -427,7 +456,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -438,6 +466,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -451,7 +480,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -462,13 +494,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -489,6 +516,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -549,6 +577,7 @@ CONFIG_MTD_PHYSMAP=y
 # CONFIG_MTD_DATAFLASH is not set
 CONFIG_MTD_M25P80=y
 CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -564,11 +593,6 @@ CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
-CONFIG_MTD_NAND_BFIN=m
-CONFIG_BFIN_NAND_BASE=0x20212000
-CONFIG_BFIN_NAND_CLE=2
-CONFIG_BFIN_NAND_ALE=1
-CONFIG_BFIN_NAND_READY=3
 CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_NAND_BF5XX is not set
 # CONFIG_MTD_NAND_DISKONCHIP is not set
@@ -578,6 +602,11 @@ CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -595,10 +624,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -622,10 +661,6 @@ CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -642,6 +677,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_SRP_ATTRS is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -666,6 +702,9 @@ CONFIG_PHYLIB=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -675,9 +714,12 @@ CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 CONFIG_BFIN_MAC_RMII=y
 # CONFIG_SMC91X is not set
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -686,15 +728,16 @@ CONFIG_BFIN_MAC_RMII=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # USB Network Adapters
@@ -744,7 +787,11 @@ CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_CM109 is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_BFIN_ROTARY is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -755,16 +802,13 @@ CONFIG_INPUT_MISC=y
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
@@ -782,6 +826,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -793,14 +838,10 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_OTP=y
 # CONFIG_BFIN_OTP_WRITE_ENABLE is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -808,6 +849,7 @@ CONFIG_BFIN_OTP=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -841,14 +883,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -865,13 +899,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -887,6 +926,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -897,11 +937,20 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -914,11 +963,13 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
 # CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -934,17 +985,24 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1111 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
 # CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83791D is not set
@@ -954,9 +1012,8 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -983,28 +1040,20 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -1026,7 +1075,6 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
@@ -1039,30 +1087,35 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
-CONFIG_HID_BRIGHT=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
-CONFIG_HID_DELL=y
+# CONFIG_HID_DRAGONRISE is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
 CONFIG_HID_PANTHERLORD=y
 # CONFIG_PANTHERLORD_FF is not set
 CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -1088,6 +1141,7 @@ CONFIG_USB_MON=y
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
 # CONFIG_USB_ISP1362_HCD is not set
@@ -1118,18 +1172,17 @@ CONFIG_USB_INVENTRA_DMA=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
@@ -1165,7 +1218,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1177,6 +1229,13 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+CONFIG_NOP_USB_XCEIV=y
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1212,6 +1271,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1223,6 +1283,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1243,10 +1304,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=m
@@ -1256,9 +1328,13 @@ CONFIG_EXT2_FS=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1268,6 +1344,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -1291,13 +1372,9 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1316,17 +1393,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1345,7 +1413,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1360,7 +1427,7 @@ CONFIG_SMB_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=m
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -1410,14 +1477,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1425,31 +1497,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1474,6 +1554,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1482,15 +1563,15 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_SECURITY_ROOTPLUG is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1522,11 +1603,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1563,6 +1646,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1570,11 +1654,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1584,6 +1670,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
new file mode 100644 (file)
index 0000000..d2dfcb0
--- /dev/null
@@ -0,0 +1,1811 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32.2
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+CONFIG_EPOLL=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_FREEZER is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF512 is not set
+# CONFIG_BF514 is not set
+# CONFIG_BF516 is not set
+# CONFIG_BF518 is not set
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+CONFIG_BF527=y
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF538 is not set
+# CONFIG_BF539 is not set
+# CONFIG_BF542_std is not set
+# CONFIG_BF542M is not set
+# CONFIG_BF544_std is not set
+# CONFIG_BF544M is not set
+# CONFIG_BF547_std is not set
+# CONFIG_BF547M is not set
+# CONFIG_BF548_std is not set
+# CONFIG_BF548M is not set
+# CONFIG_BF549_std is not set
+# CONFIG_BF549M is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_MIN=0
+CONFIG_BF_REV_MAX=2
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_0_6 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_DMA0_ERROR=7
+CONFIG_IRQ_DMAR0_BLK=7
+CONFIG_IRQ_DMAR1_BLK=7
+CONFIG_IRQ_DMAR0_OVR=7
+CONFIG_IRQ_DMAR1_OVR=7
+CONFIG_IRQ_PPI_ERROR=7
+CONFIG_IRQ_MAC_ERROR=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_UART0_ERROR=7
+CONFIG_IRQ_UART1_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_OPTSEC=11
+CONFIG_IRQ_CNT=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_PORTH_INTA=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_PORTH_INTB=11
+CONFIG_IRQ_TIMER0=8
+CONFIG_IRQ_TIMER1=12
+CONFIG_IRQ_TIMER2=12
+CONFIG_IRQ_TIMER3=12
+CONFIG_IRQ_TIMER4=12
+CONFIG_IRQ_TIMER5=12
+CONFIG_IRQ_TIMER6=12
+CONFIG_IRQ_TIMER7=12
+CONFIG_IRQ_PORTG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_PORTF_INTA=13
+CONFIG_IRQ_PORTF_INTB=13
+CONFIG_BF52x=y
+# CONFIG_BFIN527_EZKIT is not set
+CONFIG_BFIN527_EZKIT_V2=y
+# CONFIG_BFIN527_BLUETECHNIX_CM is not set
+# CONFIG_BFIN526_EZBRD is not set
+
+#
+# BF527 Specific Configuration
+#
+
+#
+# Alternative Multiplexing Scheme
+#
+# CONFIG_BF527_SPORT0_PORTF is not set
+CONFIG_BF527_SPORT0_PORTG=y
+CONFIG_BF527_SPORT0_TSCLK_PG10=y
+# CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
+CONFIG_BF527_UART1_PORTF=y
+# CONFIG_BF527_UART1_PORTG is not set
+# CONFIG_BF527_NAND_D_PORTF is not set
+CONFIG_BF527_NAND_D_PORTH=y
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_SPI_ERROR=7
+CONFIG_IRQ_NFC_ERROR=7
+CONFIG_IRQ_HDMA_ERROR=7
+CONFIG_IRQ_HDMA=7
+CONFIG_IRQ_USB_EINT=10
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Misc
+#
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_APP_STACK_L1=y
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
+CONFIG_BFIN_GPTIMERS=y
+# CONFIG_DMA_UNCACHED_4M is not set
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+CONFIG_BFIN_EXTMEM_DCACHEABLE=y
+CONFIG_BFIN_EXTMEM_WRITEBACK=y
+# CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
+
+#
+# Memory Protection Unit
+#
+# CONFIG_MPU is not set
+
+#
+# Asynchronous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B2
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_BFIN_SIR=m
+CONFIG_BFIN_SIR0=y
+CONFIG_SIR_BFIN_DMA=y
+# CONFIG_SIR_BFIN_PIO is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+# CONFIG_KINGSUN_DONGLE is not set
+# CONFIG_KSDAZZLE_DONGLE is not set
+# CONFIG_KS959_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_MCS_FIR is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_MAC_USE_L1=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+CONFIG_BFIN_MAC_RMII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ADP5520=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY 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
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+CONFIG_TOUCHSCREEN_AD7879_I2C=y
+CONFIG_TOUCHSCREEN_AD7879=y
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_BFIN_ROTARY is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BFIN_SPI_ADC is not set
+CONFIG_BFIN_SPORT=m
+# CONFIG_BFIN_TWI_LCD is not set
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BFIN_LOCK is not set
+# CONFIG_SPI_BFIN_SPORT is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5520 is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+CONFIG_PMIC_ADP5520=y
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_BFIN_T350MCQB is not set
+CONFIG_FB_BFIN_LQ035Q1=y
+# CONFIG_FB_BFIN_7393 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_BACKLIGHT_ADP5520 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_BLACKFIN_VGA16 is not set
+CONFIG_LOGO_BLACKFIN_CLUT224=y
+CONFIG_SOUND=m
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_SPI=y
+
+#
+# ALSA Blackfin devices
+#
+# CONFIG_SND_BFIN_AD73322 is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_BF5XX_I2S=m
+CONFIG_SND_BF5XX_SOC_SSM2602=m
+# CONFIG_SND_BF5XX_SOC_AD73311 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1371 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1761 is not set
+# CONFIG_SND_BF5XX_TDM is not set
+CONFIG_SND_BF5XX_AC97=m
+CONFIG_SND_BF5XX_MMAP_SUPPORT=y
+# CONFIG_SND_BF5XX_MULTICHAN_SUPPORT is not set
+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SND_BF5XX_SOC_SPORT=m
+CONFIG_SND_BF5XX_SOC_I2S=m
+CONFIG_SND_BF5XX_SOC_AC97=m
+CONFIG_SND_BF5XX_SPORT_NUM=0
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_AD1980=m
+CONFIG_SND_SOC_SSM2602=m
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
+CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# Blackfin high speed USB Support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+CONFIG_NOP_USB_XCEIV=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+CONFIG_LEDS_ADP5520=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGERS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=m
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_VERBOSE=y
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_TOMOYO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 6d1a623..edbb44d 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,29 +160,28 @@ CONFIG_BF527=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
 CONFIG_BF_REV_MAX=2
 # CONFIG_BF_REV_0_0 is not set
-# CONFIG_BF_REV_0_1 is not set
-CONFIG_BF_REV_0_2=y
+CONFIG_BF_REV_0_1=y
+# CONFIG_BF_REV_0_2 is not set
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
-CONFIG_BF52x=y
 CONFIG_MEM_MT48LC32M16A2TG_75=y
 CONFIG_IRQ_PLL_WAKEUP=7
 CONFIG_IRQ_DMA0_ERROR=7
@@ -200,7 +227,9 @@ CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
 CONFIG_IRQ_PORTF_INTA=13
 CONFIG_IRQ_PORTF_INTB=13
+CONFIG_BF52x=y
 CONFIG_BFIN527_EZKIT=y
+# CONFIG_BFIN527_EZKIT_V2 is not set
 # CONFIG_BFIN527_BLUETECHNIX_CM is not set
 # CONFIG_BFIN526_EZBRD is not set
 
@@ -318,7 +347,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -327,16 +355,18 @@ CONFIG_BFIN_GPTIMERS=y
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -347,7 +377,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -403,11 +433,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -431,7 +456,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -442,6 +466,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -455,7 +480,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -508,13 +536,8 @@ CONFIG_SIR_BFIN_DMA=y
 # CONFIG_MCS_FIR is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -535,6 +558,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -593,6 +617,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_DATAFLASH is not set
 CONFIG_MTD_M25P80=y
 CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -608,11 +633,6 @@ CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
-CONFIG_MTD_NAND_BFIN=m
-CONFIG_BFIN_NAND_BASE=0x20212000
-CONFIG_BFIN_NAND_CLE=2
-CONFIG_BFIN_NAND_ALE=1
-CONFIG_BFIN_NAND_READY=3
 CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_NAND_BF5XX is not set
 # CONFIG_MTD_NAND_DISKONCHIP is not set
@@ -622,6 +642,11 @@ CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -639,10 +664,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -666,10 +701,6 @@ CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -686,6 +717,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_SRP_ATTRS is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -710,6 +742,9 @@ CONFIG_PHYLIB=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -720,9 +755,12 @@ CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 CONFIG_BFIN_MAC_RMII=y
 # CONFIG_SMC91X is not set
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -731,15 +769,16 @@ CONFIG_BFIN_MAC_RMII=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # USB Network Adapters
@@ -789,7 +828,11 @@ CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_CM109 is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_BFIN_ROTARY is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -800,16 +843,13 @@ CONFIG_INPUT_MISC=y
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
@@ -827,6 +867,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -838,14 +879,10 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_OTP=y
 # CONFIG_BFIN_OTP_WRITE_ENABLE is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -853,6 +890,7 @@ CONFIG_BFIN_OTP=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -886,14 +924,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -910,13 +940,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -932,6 +967,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -942,11 +978,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -973,28 +1013,21 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -1030,15 +1063,18 @@ CONFIG_FB_BFIN_T350MCQB=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LMS283GF05 is not set
 CONFIG_LCD_LTV350QV=m
 # CONFIG_LCD_ILI9320 is not set
 # CONFIG_LCD_TDO24M is not set
 # CONFIG_LCD_VGG2432A4 is not set
 # CONFIG_LCD_PLATFORM is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=m
-# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_BACKLIGHT_ADP8870 is not set
 
 #
 # Display device support
@@ -1066,6 +1102,7 @@ CONFIG_SOUND=m
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 # CONFIG_SND_MIXER_OSS is not set
 # CONFIG_SND_PCM_OSS is not set
@@ -1074,6 +1111,11 @@ CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_DRIVERS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
@@ -1084,7 +1126,6 @@ CONFIG_SND_SPI=y
 #
 # ALSA Blackfin devices
 #
-# CONFIG_SND_BLACKFIN_AD1836 is not set
 # CONFIG_SND_BFIN_AD73322 is not set
 CONFIG_SND_USB=y
 # CONFIG_SND_USB_AUDIO is not set
@@ -1094,15 +1135,19 @@ CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_BF5XX_I2S=m
 CONFIG_SND_BF5XX_SOC_SSM2602=m
 # CONFIG_SND_BF5XX_SOC_AD73311 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1371 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1761 is not set
+# CONFIG_SND_BF5XX_TDM is not set
 CONFIG_SND_BF5XX_AC97=m
 CONFIG_SND_BF5XX_MMAP_SUPPORT=y
 # CONFIG_SND_BF5XX_MULTICHAN_SUPPORT is not set
+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SOC_SPORT=m
 CONFIG_SND_BF5XX_SOC_I2S=m
 CONFIG_SND_BF5XX_SOC_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SPORT_NUM=0
-# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_SOC_I2C_AND_SPI=m
 # CONFIG_SND_SOC_ALL_CODECS is not set
 CONFIG_SND_SOC_AD1980=m
 CONFIG_SND_SOC_SSM2602=m
@@ -1110,7 +1155,6 @@ CONFIG_SND_SOC_SSM2602=m
 CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
@@ -1123,30 +1167,35 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
-CONFIG_HID_BRIGHT=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
-CONFIG_HID_DELL=y
+# CONFIG_HID_DRAGONRISE is not set
 CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
 # CONFIG_LOGIRUMBLEPAD2_FF is not set
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
 CONFIG_HID_PANTHERLORD=y
 # CONFIG_PANTHERLORD_FF is not set
 CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -1172,6 +1221,7 @@ CONFIG_USB_MON=y
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
 # CONFIG_USB_ISP1362_HCD is not set
@@ -1188,9 +1238,7 @@ CONFIG_USB_MUSB_HOST=y
 # CONFIG_USB_MUSB_PERIPHERAL is not set
 # CONFIG_USB_MUSB_OTG is not set
 CONFIG_USB_MUSB_HDRC_HCD=y
-# CONFIG_MUSB_PIO_ONLY is not set
-CONFIG_USB_INVENTRA_DMA=y
-# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_MUSB_PIO_ONLY=y
 # CONFIG_USB_MUSB_DEBUG is not set
 
 #
@@ -1202,18 +1250,17 @@ CONFIG_USB_INVENTRA_DMA=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
@@ -1249,7 +1296,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1261,6 +1307,13 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+CONFIG_NOP_USB_XCEIV=y
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1296,6 +1349,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1307,6 +1361,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1327,10 +1382,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=m
@@ -1340,9 +1406,13 @@ CONFIG_EXT2_FS=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1352,6 +1422,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -1376,13 +1451,9 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1401,17 +1472,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1430,7 +1492,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1445,7 +1506,7 @@ CONFIG_SMB_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=m
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -1495,14 +1556,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1510,31 +1576,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1559,6 +1633,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1567,15 +1642,15 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_SECURITY_ROOTPLUG is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1607,11 +1682,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1648,6 +1725,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1655,11 +1733,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1669,6 +1749,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 50f9a23..0b13d58 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_BF533=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=3
@@ -228,7 +256,7 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_TICKSOURCE_GPTMR0 is not set
 CONFIG_TICKSOURCE_CORETMR=y
-# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_CYCLES_CLOCKSOURCE=y
 # CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
@@ -280,7 +308,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -289,19 +316,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
-#
-# Cache Support
-#
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -312,7 +338,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -358,6 +384,7 @@ CONFIG_PM=y
 CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
+# CONFIG_PM_RUNTIME is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_PM_BFIN_SLEEP_DEEPER=y
 # CONFIG_PM_BFIN_SLEEP is not set
@@ -379,11 +406,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -407,7 +429,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -418,6 +439,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -431,7 +453,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -475,13 +500,8 @@ CONFIG_IRTTY_SIR=m
 #
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -502,6 +522,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -559,6 +580,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -574,6 +596,11 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -590,9 +617,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -616,9 +648,12 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_SMC91X=y
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -627,15 +662,16 @@ CONFIG_SMC91X=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -679,15 +715,12 @@ CONFIG_INPUT_EVDEV=m
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
-# CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_BFIN_JTAG_COMM=m
@@ -701,6 +734,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -711,12 +745,8 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -734,13 +764,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -753,9 +788,6 @@ CONFIG_GPIO_SYSFS=y
 #
 # I2C GPIO expanders:
 #
-# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_PCA953X is not set
-# CONFIG_GPIO_PCF857X is not set
 
 #
 # PCI GPIO expanders:
@@ -766,11 +798,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -793,23 +829,10 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -826,14 +849,12 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=m
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -864,6 +885,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -884,10 +906,20 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -896,9 +928,13 @@ CONFIG_RTC_DRV_BFIN=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -908,6 +944,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -926,13 +967,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -951,17 +988,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -980,7 +1008,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1045,14 +1072,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1060,31 +1092,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1109,6 +1149,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1117,14 +1158,14 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1156,11 +1197,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1197,6 +1240,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1204,11 +1248,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1218,6 +1264,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 6c60c82..c3fe6e5 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_BF533=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=3
@@ -228,7 +256,7 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_TICKSOURCE_GPTMR0 is not set
 CONFIG_TICKSOURCE_CORETMR=y
-# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_CYCLES_CLOCKSOURCE=y
 # CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
@@ -280,7 +308,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -289,16 +316,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -309,7 +338,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -355,6 +384,7 @@ CONFIG_PM=y
 CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
+# CONFIG_PM_RUNTIME is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_PM_BFIN_SLEEP_DEEPER=y
 # CONFIG_PM_BFIN_SLEEP is not set
@@ -376,11 +406,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -404,7 +429,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -415,6 +439,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -428,7 +453,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -474,13 +502,8 @@ CONFIG_SIR_BFIN_DMA=y
 #
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -501,6 +524,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -560,6 +584,7 @@ CONFIG_MTD_BFIN_ASYNC=m
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -575,6 +600,11 @@ CONFIG_MTD_BFIN_ASYNC=m
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -591,10 +621,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -618,9 +658,12 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_SMC91X=y
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -629,15 +672,16 @@ CONFIG_SMC91X=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -672,7 +716,10 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_UINPUT is not set
-CONFIG_CONFIG_INPUT_PCF8574=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -683,16 +730,13 @@ CONFIG_CONFIG_INPUT_PCF8574=m
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_BFIN_JTAG_COMM=m
@@ -706,6 +750,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -716,12 +761,8 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -729,6 +770,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=m
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -759,14 +801,6 @@ CONFIG_I2C_HELPER_AUTO=y
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -783,13 +817,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -805,6 +844,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -815,11 +855,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -841,26 +885,18 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -904,6 +940,7 @@ CONFIG_ADV7393_1XMEM=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -913,19 +950,27 @@ CONFIG_ADV7393_1XMEM=y
 # CONFIG_LOGO is not set
 CONFIG_SOUND=m
 CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
 # CONFIG_SND_DYNAMIC_MINORS is not set
 CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_DRIVERS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
@@ -936,13 +981,6 @@ CONFIG_SND_SPI=y
 #
 # ALSA Blackfin devices
 #
-CONFIG_SND_BLACKFIN_AD1836=m
-CONFIG_SND_BLACKFIN_AD1836_TDM=y
-# CONFIG_SND_BLACKFIN_AD1836_I2S is not set
-CONFIG_SND_BLACKFIN_AD1836_MULSUB=y
-# CONFIG_SND_BLACKFIN_AD1836_5P1 is not set
-CONFIG_SND_BLACKFIN_SPORT=0
-CONFIG_SND_BLACKFIN_SPI_PFBIT=4
 CONFIG_SND_BFIN_SPORT=0
 CONFIG_SND_BFIN_AD73322=m
 CONFIG_SND_BFIN_AD73322_SPORT0_SE=10
@@ -953,16 +991,20 @@ CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_BF5XX_I2S=m
 # CONFIG_SND_BF5XX_SOC_SSM2602 is not set
 CONFIG_SND_BF5XX_SOC_AD73311=m
+# CONFIG_SND_BF5XX_SOC_ADAU1371 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1761 is not set
 CONFIG_SND_BFIN_AD73311_SE=4
+# CONFIG_SND_BF5XX_TDM is not set
 CONFIG_SND_BF5XX_AC97=m
 CONFIG_SND_BF5XX_MMAP_SUPPORT=y
 # CONFIG_SND_BF5XX_MULTICHAN_SUPPORT is not set
+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SOC_SPORT=m
 CONFIG_SND_BF5XX_SOC_I2S=m
 CONFIG_SND_BF5XX_SOC_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SPORT_NUM=0
-# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_SOC_I2C_AND_SPI=m
 # CONFIG_SND_SOC_ALL_CODECS is not set
 CONFIG_SND_SOC_AD1980=m
 CONFIG_SND_SOC_AD73311=m
@@ -970,14 +1012,12 @@ CONFIG_SND_SOC_AD73311=m
 CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1014,6 +1054,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1025,6 +1066,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1045,10 +1087,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -1057,9 +1110,13 @@ CONFIG_RTC_DRV_BFIN=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1069,6 +1126,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1087,13 +1149,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1112,17 +1170,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1141,7 +1190,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1206,14 +1254,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1221,31 +1274,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1270,6 +1331,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1278,14 +1340,14 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1317,11 +1379,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1358,6 +1422,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1365,11 +1430,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1379,6 +1446,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 2908595..7596cf7 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_FREEZER=y
 CONFIG_BF537=y
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=2
@@ -184,7 +212,8 @@ CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
 CONFIG_IRQ_SPI=10
 CONFIG_BFIN537_STAMP=y
-# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM_E is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM_U is not set
 # CONFIG_BFIN537_BLUETECHNIX_TCM is not set
 # CONFIG_PNAV10 is not set
 # CONFIG_CAMSIG_MINOTAUR is not set
@@ -235,7 +264,7 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_TICKSOURCE_GPTMR0 is not set
 CONFIG_TICKSOURCE_CORETMR=y
-# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_CYCLES_CLOCKSOURCE=y
 # CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
@@ -287,7 +316,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -296,16 +324,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -316,7 +346,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -362,6 +392,7 @@ CONFIG_PM=y
 CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
+# CONFIG_PM_RUNTIME is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_PM_BFIN_SLEEP_DEEPER=y
 # CONFIG_PM_BFIN_SLEEP is not set
@@ -384,11 +415,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -412,7 +438,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -423,6 +448,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -436,14 +462,34 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+CONFIG_CAN_DEV=m
+# CONFIG_CAN_CALC_BITTIMING is not set
+CONFIG_CAN_BFIN=m
+# CONFIG_CAN_SJA1000 is not set
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
 CONFIG_IRDA=m
 
 #
@@ -483,13 +529,8 @@ CONFIG_SIR_BFIN_DMA=y
 #
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -510,6 +551,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -568,6 +610,7 @@ CONFIG_MTD_PHYSMAP=m
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -583,6 +626,11 @@ CONFIG_MTD_PHYSMAP=m
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -599,10 +647,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -637,6 +695,9 @@ CONFIG_SMSC_PHY=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -647,9 +708,12 @@ CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_BFIN_MAC_RMII is not set
 # CONFIG_SMC91X is not set
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -658,15 +722,16 @@ CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -701,7 +766,10 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_UINPUT is not set
-CONFIG_CONFIG_INPUT_PCF8574=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -712,16 +780,13 @@ CONFIG_CONFIG_INPUT_PCF8574=m
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_BFIN_JTAG_COMM=m
@@ -735,6 +800,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -746,17 +812,8 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-CONFIG_CAN4LINUX=y
-
-#
-# linux embedded drivers
-#
-CONFIG_CAN_BLACKFIN=m
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -764,6 +821,7 @@ CONFIG_CAN_BLACKFIN=m
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=m
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -796,14 +854,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-CONFIG_SENSORS_AD5252=m
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -820,13 +870,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -842,6 +897,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -852,11 +908,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -878,26 +938,18 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -929,9 +981,6 @@ CONFIG_FB_CFB_IMAGEBLIT=m
 # CONFIG_FB_BFIN_T350MCQB is not set
 # CONFIG_FB_BFIN_LQ035Q1 is not set
 CONFIG_FB_BF537_LQ035=m
-CONFIG_LQ035_SLAVE_ADDR=0x58
-# CONFIG_FB_BFIN_LANDSCAPE is not set
-# CONFIG_FB_BFIN_BGR is not set
 CONFIG_FB_BFIN_7393=m
 CONFIG_NTSC=y
 # CONFIG_PAL is not set
@@ -946,15 +995,18 @@ CONFIG_ADV7393_1XMEM=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LMS283GF05 is not set
 # CONFIG_LCD_LTV350QV is not set
 # CONFIG_LCD_ILI9320 is not set
 # CONFIG_LCD_TDO24M is not set
 # CONFIG_LCD_VGG2432A4 is not set
 # CONFIG_LCD_PLATFORM is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=m
-CONFIG_BACKLIGHT_CORGI=m
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_BACKLIGHT_ADP8870 is not set
 
 #
 # Display device support
@@ -963,19 +1015,27 @@ CONFIG_BACKLIGHT_CORGI=m
 # CONFIG_LOGO is not set
 CONFIG_SOUND=m
 CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
 # CONFIG_SND_DYNAMIC_MINORS is not set
 CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_DRIVERS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
@@ -986,13 +1046,6 @@ CONFIG_SND_SPI=y
 #
 # ALSA Blackfin devices
 #
-CONFIG_SND_BLACKFIN_AD1836=m
-CONFIG_SND_BLACKFIN_AD1836_TDM=y
-# CONFIG_SND_BLACKFIN_AD1836_I2S is not set
-CONFIG_SND_BLACKFIN_AD1836_MULSUB=y
-# CONFIG_SND_BLACKFIN_AD1836_5P1 is not set
-CONFIG_SND_BLACKFIN_SPORT=0
-CONFIG_SND_BLACKFIN_SPI_PFBIT=4
 CONFIG_SND_BFIN_SPORT=0
 CONFIG_SND_BFIN_AD73322=m
 CONFIG_SND_BFIN_AD73322_SPORT0_SE=10
@@ -1003,16 +1056,20 @@ CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_BF5XX_I2S=m
 # CONFIG_SND_BF5XX_SOC_SSM2602 is not set
 CONFIG_SND_BF5XX_SOC_AD73311=m
+# CONFIG_SND_BF5XX_SOC_ADAU1371 is not set
+# CONFIG_SND_BF5XX_SOC_ADAU1761 is not set
 CONFIG_SND_BFIN_AD73311_SE=4
+# CONFIG_SND_BF5XX_TDM is not set
 CONFIG_SND_BF5XX_AC97=m
 CONFIG_SND_BF5XX_MMAP_SUPPORT=y
 # CONFIG_SND_BF5XX_MULTICHAN_SUPPORT is not set
+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SOC_SPORT=m
 CONFIG_SND_BF5XX_SOC_I2S=m
 CONFIG_SND_BF5XX_SOC_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 CONFIG_SND_BF5XX_SPORT_NUM=0
-# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_SOC_I2C_AND_SPI=m
 # CONFIG_SND_SOC_ALL_CODECS is not set
 CONFIG_SND_SOC_AD1980=m
 CONFIG_SND_SOC_AD73311=m
@@ -1020,14 +1077,12 @@ CONFIG_SND_SOC_AD73311=m
 CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1064,6 +1119,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1075,6 +1131,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1095,10 +1152,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -1107,9 +1175,13 @@ CONFIG_RTC_DRV_BFIN=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1119,6 +1191,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1137,13 +1214,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1162,17 +1235,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1191,7 +1255,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1256,14 +1319,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1271,31 +1339,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1320,6 +1396,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1328,14 +1405,14 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1367,11 +1444,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1408,6 +1487,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1415,11 +1495,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1429,6 +1511,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 09ea249..bc1871d 100644 (file)
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
-# Thu May 21 05:50:01 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -26,22 +31,41 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -62,6 +86,10 @@ CONFIG_EPOLL=y
 # CONFIG_TIMERFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -69,11 +97,15 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -81,11 +113,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -101,7 +130,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -132,15 +160,15 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_BF537 is not set
 CONFIG_BF538=y
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=4
@@ -246,7 +274,7 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_TICKSOURCE_GPTMR0 is not set
 CONFIG_TICKSOURCE_CORETMR=y
-# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_CYCLES_CLOCKSOURCE=y
 # CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
@@ -298,7 +326,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -307,16 +334,18 @@ CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -327,7 +356,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -383,11 +412,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -411,7 +435,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -422,6 +445,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -435,14 +459,34 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+CONFIG_CAN_DEV=m
+# CONFIG_CAN_CALC_BITTIMING is not set
+CONFIG_CAN_BFIN=m
+# CONFIG_CAN_SJA1000 is not set
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
 CONFIG_IRDA=m
 
 #
@@ -481,13 +525,8 @@ CONFIG_SIR_BFIN_DMA=y
 #
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -508,6 +547,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -566,6 +606,7 @@ CONFIG_MTD_PHYSMAP=m
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -581,11 +622,6 @@ CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
-CONFIG_MTD_NAND_BFIN=m
-CONFIG_BFIN_NAND_BASE=0x20212000
-CONFIG_BFIN_NAND_CLE=2
-CONFIG_BFIN_NAND_ALE=1
-CONFIG_BFIN_NAND_READY=3
 CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -593,6 +629,11 @@ CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -643,14 +684,20 @@ CONFIG_SMSC_PHY=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_SMC91X=y
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -659,15 +706,16 @@ CONFIG_SMC91X=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -700,14 +748,17 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_AD7877 is not set
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 CONFIG_TOUCHSCREEN_AD7879_SPI=y
 CONFIG_TOUCHSCREEN_AD7879=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
@@ -715,9 +766,13 @@ CONFIG_TOUCHSCREEN_AD7879=y
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -728,16 +783,13 @@ CONFIG_INPUT_MISC=y
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_BFIN_JTAG_COMM=m
@@ -751,6 +803,7 @@ CONFIG_BFIN_JTAG_COMM=m
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -765,12 +818,8 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -778,6 +827,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=m
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 # CONFIG_I2C_CHARDEV is not set
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -810,14 +860,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -834,13 +876,18 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
@@ -856,6 +903,7 @@ CONFIG_GPIO_SYSFS=y
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -866,11 +914,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -892,26 +944,17 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -947,6 +990,7 @@ CONFIG_FB_BFIN_LQ035Q1=m
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -957,14 +1001,12 @@ CONFIG_FB_BFIN_LQ035Q1=m
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
 #
 # Special HID drivers
 #
-CONFIG_HID_COMPAT=y
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1001,6 +1043,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1012,6 +1055,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1032,10 +1076,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 # CONFIG_EXT2_FS is not set
@@ -1044,9 +1099,13 @@ CONFIG_RTC_DRV_BFIN=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1056,6 +1115,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1074,13 +1138,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1099,17 +1159,8 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1128,7 +1179,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1193,14 +1243,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1208,31 +1263,39 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1257,6 +1320,7 @@ CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1265,14 +1329,14 @@ CONFIG_ACCESS_CHECK=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1304,11 +1368,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1345,6 +1411,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1352,11 +1419,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1366,6 +1435,8 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index eb3e98b..ca309cf 100644 (file)
@@ -1,7 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31.5
-# Mon Nov  2 22:02:56 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -12,7 +11,6 @@ CONFIG_GENERIC_CSUM=y
 CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -49,11 +47,12 @@ CONFIG_SYSVIPC_SYSCTL=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
 # CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -89,24 +88,23 @@ CONFIG_EPOLL=y
 # CONFIG_AIO is not set
 
 #
-# Performance Counters
+# Kernel Performance Events And Counters
 #
 CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 
 #
 # GCOV-based kernel profiling
 #
 # CONFIG_GCOV_KERNEL is not set
-# CONFIG_SLOW_WORK is not set
+CONFIG_SLOW_WORK=y
+# CONFIG_SLOW_WORK_DEBUG is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_BASE_SMALL=0
@@ -163,15 +161,15 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
 CONFIG_BF548_std=y
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
@@ -185,7 +183,6 @@ CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
-CONFIG_BF54x=y
 CONFIG_IRQ_PLL_WAKEUP=7
 CONFIG_IRQ_RTC=8
 CONFIG_IRQ_SPORT0_RX=9
@@ -221,6 +218,8 @@ CONFIG_IRQ_SPI1=10
 CONFIG_IRQ_SPI2=10
 CONFIG_IRQ_TWI0=11
 CONFIG_IRQ_TWI1=11
+CONFIG_BF548=y
+CONFIG_BF54x=y
 CONFIG_BFIN548_EZKIT=y
 # CONFIG_BFIN548_BLUETECHNIX_CM is not set
 
@@ -387,12 +386,14 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
 CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 CONFIG_DMA_UNCACHED_2M=y
 # CONFIG_DMA_UNCACHED_1M is not set
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
@@ -505,6 +506,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -528,7 +530,24 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+CONFIG_CAN_DEV=m
+# CONFIG_CAN_CALC_BITTIMING is not set
+CONFIG_CAN_BFIN=m
+# CONFIG_CAN_SJA1000 is not set
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
 CONFIG_IRDA=m
 
 #
@@ -663,6 +682,7 @@ CONFIG_MTD_PHYSMAP=y
 # CONFIG_MTD_DATAFLASH is not set
 CONFIG_MTD_M25P80=y
 CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -711,10 +731,10 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_ISL29003 is not set
-# CONFIG_AD525X_DPOT is not set
 # CONFIG_C2PORT is not set
 
 #
@@ -767,7 +787,8 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_OSD_INITIATOR is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
-CONFIG_SATA_PMP=y
+CONFIG_ATA_VERBOSE_ERROR=y
+# CONFIG_SATA_PMP is not set
 CONFIG_ATA_SFF=y
 # CONFIG_SATA_MV is not set
 # CONFIG_PATA_PLATFORM is not set
@@ -808,6 +829,7 @@ CONFIG_MII=y
 # CONFIG_ETHOC is not set
 CONFIG_SMSC911X=y
 # CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -818,12 +840,10 @@ CONFIG_SMSC911X=y
 # CONFIG_B44 is not set
 # CONFIG_KS8842 is not set
 # CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
 # CONFIG_WLAN_PRE80211 is not set
 CONFIG_WLAN_80211=y
 CONFIG_LIBERTAS=m
@@ -877,10 +897,12 @@ CONFIG_INPUT_EVBUG=m
 CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_ADP5588 is not set
 # CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_QT2160 is not set
 CONFIG_KEYBOARD_BFIN=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_GPIO is not set
 # CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_OPENCORES is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
@@ -900,6 +922,7 @@ CONFIG_TOUCHSCREEN_AD7877=m
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
@@ -910,7 +933,6 @@ CONFIG_TOUCHSCREEN_AD7877=m
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_TOUCHSCREEN_W90X900 is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_ATI_REMOTE is not set
 # CONFIG_INPUT_ATI_REMOTE2 is not set
@@ -976,11 +998,6 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_OTP=y
 # CONFIG_BFIN_OTP_WRITE_ENABLE is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -988,6 +1005,7 @@ CONFIG_BFIN_OTP=y
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -1021,9 +1039,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -1078,11 +1093,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -1116,8 +1135,10 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
 # CONFIG_AB3100_CORE is not set
 # CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
@@ -1192,6 +1213,7 @@ CONFIG_LOGO=y
 CONFIG_LOGO_BLACKFIN_CLUT224=y
 CONFIG_SOUND=y
 CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
@@ -1245,7 +1267,6 @@ CONFIG_SND_SOC_AD1980=y
 CONFIG_AC97_BUS=y
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 
 #
@@ -1268,6 +1289,7 @@ CONFIG_HID_CYPRESS=y
 CONFIG_HID_EZKEY=y
 # CONFIG_HID_KYE is not set
 CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
 # CONFIG_HID_KENSINGTON is not set
 CONFIG_HID_LOGITECH=y
 # CONFIG_LOGITECH_FF is not set
@@ -1422,10 +1444,11 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
 CONFIG_SDH_BFIN=y
 # CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND is not set
-# CONFIG_SDH_BFIN_ENABLE_SDIO_IRQ is not set
-# CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
 # CONFIG_ACCESSIBILITY is not set
@@ -1472,6 +1495,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1522,6 +1546,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_FILE_LOCKING=y
 CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
@@ -1563,7 +1588,6 @@ CONFIG_NTFS_RW=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
 CONFIG_MISC_FILESYSTEMS=y
@@ -1595,7 +1619,6 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
@@ -1680,6 +1703,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
@@ -1714,12 +1738,14 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
@@ -1730,7 +1756,6 @@ CONFIG_TRACING_SUPPORT=y
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
-# CONFIG_KMEMCHECK is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
@@ -1766,7 +1791,6 @@ CONFIG_CRYPTO=y
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1798,11 +1822,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
index b9b0f93..6a776ce 100644 (file)
@@ -114,7 +114,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
 
@@ -1486,19 +1486,10 @@ CONFIG_DEBUG_INFO=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_ENABLE_DEFAULT_TRACERS is not set
-# CONFIG_BOOT_TRACER is not set
-CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
 # CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
 # CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
index e3ecdcc..792ff09 100644 (file)
@@ -1,7 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31.5
-# Mon Nov  2 21:59:31 2009
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -12,7 +11,6 @@ CONFIG_GENERIC_CSUM=y
 CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -49,11 +47,12 @@ CONFIG_SYSVIPC_SYSCTL=y
 #
 # RCU Subsystem
 #
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
 # CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -89,17 +88,15 @@ CONFIG_EPOLL=y
 # CONFIG_AIO is not set
 
 #
-# Performance Counters
+# Kernel Performance Events And Counters
 #
 CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 
 #
@@ -163,15 +160,15 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_BF537 is not set
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 CONFIG_BF561=y
 # CONFIG_SMP is not set
@@ -180,9 +177,9 @@ CONFIG_BF_REV_MAX=5
 # CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
 # CONFIG_BF_REV_0_2 is not set
-# CONFIG_BF_REV_0_3 is not set
+CONFIG_BF_REV_0_3=y
 # CONFIG_BF_REV_0_4 is not set
-CONFIG_BF_REV_0_5=y
+# CONFIG_BF_REV_0_5 is not set
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
@@ -298,7 +295,7 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_TICKSOURCE_GPTMR0 is not set
 CONFIG_TICKSOURCE_CORETMR=y
-# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_CYCLES_CLOCKSOURCE=y
 # CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
@@ -353,12 +350,14 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
 CONFIG_BFIN_GPTIMERS=m
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
@@ -370,9 +369,11 @@ CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
-CONFIG_BFIN_EXTMEM_WRITEBACK=y
-# CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
-# CONFIG_BFIN_L2_DCACHEABLE is not set
+# CONFIG_BFIN_EXTMEM_WRITEBACK is not set
+CONFIG_BFIN_EXTMEM_WRITETHROUGH=y
+CONFIG_BFIN_L2_DCACHEABLE=y
+# CONFIG_BFIN_L2_WRITEBACK is not set
+CONFIG_BFIN_L2_WRITETHROUGH=y
 
 #
 # Memory Protection Unit
@@ -472,6 +473,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -613,6 +615,7 @@ CONFIG_MTD_PHYSMAP=m
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -685,6 +688,7 @@ CONFIG_SMC91X=y
 # CONFIG_ETHOC is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -695,14 +699,10 @@ CONFIG_SMC91X=y
 # CONFIG_B44 is not set
 # CONFIG_KS8842 is not set
 # CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+# CONFIG_WLAN is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -782,11 +782,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-# CONFIG_CAN4LINUX is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
@@ -838,11 +833,15 @@ CONFIG_GPIO_SYSFS=y
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 
@@ -865,6 +864,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_MC13783 is not set
 # CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
@@ -884,7 +884,6 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=m
-# CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
 # CONFIG_HID_PID is not set
 
@@ -923,6 +922,7 @@ CONFIG_HID=m
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_FILE_LOCKING=y
 CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
@@ -957,7 +957,6 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
 CONFIG_MISC_FILESYSTEMS=y
@@ -989,7 +988,6 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
@@ -1064,6 +1062,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
@@ -1098,26 +1097,24 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 # CONFIG_FRAME_POINTER is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_TRACING_SUPPORT=y
 # CONFIG_FTRACE is not set
-# CONFIG_BRANCH_PROFILE_NONE is not set
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
-# CONFIG_KMEMCHECK is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
@@ -1153,7 +1150,6 @@ CONFIG_CRYPTO=y
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1185,11 +1181,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
index bc7fae3..ed0a7eb 100644 (file)
@@ -834,13 +834,6 @@ CONFIG_SND_VERBOSE_PROCFS=y
 #
 # ALSA Blackfin devices
 #
-CONFIG_SND_BLACKFIN_AD1836=m
-CONFIG_SND_BLACKFIN_AD1836_TDM=y
-# CONFIG_SND_BLACKFIN_AD1836_I2S is not set
-CONFIG_SND_BLACKFIN_AD1836_MULSUB=y
-# CONFIG_SND_BLACKFIN_AD1836_5P1 is not set
-CONFIG_SND_BLACKFIN_SPORT=0
-CONFIG_SND_BLACKFIN_SPI_PFBIT=4
 # CONFIG_SND_BFIN_AD73311 is not set
 
 #
index 67d1276..ad58fed 100644 (file)
@@ -1,21 +1,27 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.10
+# Linux kernel version: 2.6.32.2
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
 CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -25,16 +31,32 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
@@ -58,6 +80,10 @@ CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 # CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
@@ -65,11 +91,14 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -77,11 +106,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -97,7 +123,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
@@ -128,15 +153,15 @@ CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF537=y
 # CONFIG_BF538 is not set
 # CONFIG_BF539 is not set
-# CONFIG_BF542 is not set
+# CONFIG_BF542_std is not set
 # CONFIG_BF542M is not set
-# CONFIG_BF544 is not set
+# CONFIG_BF544_std is not set
 # CONFIG_BF544M is not set
-# CONFIG_BF547 is not set
+# CONFIG_BF547_std is not set
 # CONFIG_BF547M is not set
-# CONFIG_BF548 is not set
+# CONFIG_BF548_std is not set
 # CONFIG_BF548M is not set
-# CONFIG_BF549 is not set
+# CONFIG_BF549_std is not set
 # CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=2
@@ -180,7 +205,8 @@ CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
 CONFIG_IRQ_SPI=10
 # CONFIG_BFIN537_STAMP is not set
-# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM_E is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM_U is not set
 # CONFIG_BFIN537_BLUETECHNIX_TCM is not set
 CONFIG_PNAV10=y
 # CONFIG_CAMSIG_MINOTAUR is not set
@@ -282,7 +308,6 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
@@ -291,16 +316,18 @@ CONFIG_BFIN_GPTIMERS=y
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
 # CONFIG_DMA_UNCACHED_NONE is not set
 
 #
 # Cache Support
 #
 CONFIG_BFIN_ICACHE=y
-# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_DCACHE_BANKA is not set
-CONFIG_BFIN_EXTMEM_ICACHEABLE=y
 CONFIG_BFIN_EXTMEM_DCACHEABLE=y
 CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
@@ -311,7 +338,7 @@ CONFIG_BFIN_EXTMEM_WRITEBACK=y
 # CONFIG_MPU is not set
 
 #
-# Asynchonous Memory Configuration
+# Asynchronous Memory Configuration
 #
 
 #
@@ -367,11 +394,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -395,7 +417,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
@@ -406,6 +427,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -419,7 +441,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -430,13 +455,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -455,6 +475,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
@@ -506,6 +527,7 @@ CONFIG_MTD_UCLINUX=y
 #
 # CONFIG_MTD_DATAFLASH is not set
 # CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -521,11 +543,6 @@ CONFIG_MTD_NAND=y
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
-CONFIG_MTD_NAND_BFIN=y
-CONFIG_BFIN_NAND_BASE=0x20100000
-CONFIG_BFIN_NAND_CLE=2
-CONFIG_BFIN_NAND_ALE=1
-CONFIG_BFIN_NAND_READY=44
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -533,6 +550,11 @@ CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -549,10 +571,20 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_AD525X_DPOT is not set
 # CONFIG_ICS932S401 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
 # CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -587,6 +619,9 @@ CONFIG_PHYLIB=y
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_ICPLUS_PHY is not set
 # CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -597,9 +632,12 @@ CONFIG_BFIN_TX_DESC_NUM=100
 CONFIG_BFIN_RX_DESC_NUM=100
 CONFIG_BFIN_MAC_RMII=y
 # CONFIG_SMC91X is not set
-# CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -608,15 +646,16 @@ CONFIG_BFIN_MAC_RMII=y
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 
 #
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -649,14 +688,17 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 CONFIG_TOUCHSCREEN_AD7877=y
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
@@ -665,6 +707,7 @@ CONFIG_TOUCHSCREEN_AD7877=y
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_ATI_REMOTE is not set
 # CONFIG_INPUT_ATI_REMOTE2 is not set
@@ -673,7 +716,9 @@ CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_CM109 is not set
 CONFIG_INPUT_UINPUT=y
-# CONFIG_CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
 
 #
 # Hardware I/O ports
@@ -684,16 +729,13 @@ CONFIG_INPUT_UINPUT=y
 #
 # Character devices
 #
-# CONFIG_AD9960 is not set
 CONFIG_BFIN_DMA_INTERFACE=m
 # CONFIG_BFIN_PPI is not set
 # CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
-# CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_BFIN_TWI_LCD is not set
-# CONFIG_SIMPLE_GPIO is not set
 # CONFIG_VT is not set
 CONFIG_DEVKMEM=y
 # CONFIG_BFIN_JTAG_COMM is not set
@@ -707,6 +749,7 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MAX3100 is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_DMA=y
@@ -719,24 +762,17 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_BFIN_SPORT is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# CAN, the car bus and industrial fieldbus
-#
-CONFIG_CAN4LINUX=y
-
-#
-# linux embedded drivers
-#
-CONFIG_CAN_BLACKFIN=m
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_HELPER_AUTO=y
 
@@ -769,14 +805,6 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_SENSORS_AD5252 is not set
-# CONFIG_EEPROM_LEGACY is not set
-CONFIG_SENSORS_PCF8574=m
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -792,20 +820,29 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_BFIN_LOCK is not set
 # CONFIG_SPI_BFIN_SPORT is not set
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_EEPROM_AT25 is not set
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 # CONFIG_GPIOLIB is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -818,11 +855,13 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
 # CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -838,17 +877,24 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1111 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
 # CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83791D is not set
@@ -858,9 +904,8 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
 # CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -875,28 +920,19 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -928,24 +964,24 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_BFIN_T350MCQB is not set
 # CONFIG_FB_BFIN_LQ035Q1 is not set
 CONFIG_FB_BF537_LQ035=y
-CONFIG_LQ035_SLAVE_ADDR=0x58
-CONFIG_FB_BFIN_LANDSCAPE=y
-# CONFIG_FB_BFIN_BGR is not set
 # CONFIG_FB_BFIN_7393 is not set
 # CONFIG_FB_HITACHI_TX09 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LMS283GF05 is not set
 # CONFIG_LCD_LTV350QV is not set
 # CONFIG_LCD_ILI9320 is not set
 # CONFIG_LCD_TDO24M is not set
 # CONFIG_LCD_VGG2432A4 is not set
 # CONFIG_LCD_PLATFORM is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_ADP8870 is not set
 
 #
 # Display device support
@@ -954,6 +990,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_LOGO is not set
 CONFIG_SOUND=y
 CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
 CONFIG_SND=m
 # CONFIG_SND_SEQUENCER is not set
 # CONFIG_SND_MIXER_OSS is not set
@@ -963,6 +1000,11 @@ CONFIG_SND=m
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_DRIVERS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
@@ -973,7 +1015,6 @@ CONFIG_SND_SPI=y
 #
 # ALSA Blackfin devices
 #
-# CONFIG_SND_BLACKFIN_AD1836 is not set
 # CONFIG_SND_BFIN_AD73322 is not set
 # CONFIG_SND_SOC is not set
 CONFIG_SOUND_PRIME=y
@@ -993,9 +1034,13 @@ CONFIG_USB_ARCH_HAS_HCD=y
 #
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 # CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1031,6 +1076,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1042,6 +1088,7 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
 # CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
 
 #
 # Platform RTC drivers
@@ -1062,10 +1109,21 @@ CONFIG_RTC_INTF_DEV=y
 #
 CONFIG_RTC_DRV_BFIN=y
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -1078,9 +1136,13 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # 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_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1090,6 +1152,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1108,13 +1175,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1123,17 +1186,8 @@ CONFIG_SYSFS=y
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS2_FS is not set
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1152,7 +1206,6 @@ CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1217,18 +1270,19 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 # CONFIG_DEBUG_KERNEL is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
-
-#
-# Tracers
-#
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 CONFIG_DEBUG_VERBOSE=y
@@ -1245,6 +1299,7 @@ CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_CPLB_INFO is not set
 # CONFIG_ACCESS_CHECK is not set
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
 
 #
 # Security options
@@ -1253,14 +1308,14 @@ CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
 CONFIG_SECURITY=y
 # CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
-# CONFIG_CRYPTO_FIPS is not set
 # CONFIG_CRYPTO_MANAGER is not set
 # CONFIG_CRYPTO_MANAGER2 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
@@ -1292,11 +1347,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
 
 #
 # Digest
 #
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1333,6 +1390,7 @@ CONFIG_CRYPTO=y
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
 
 #
@@ -1340,11 +1398,13 @@ CONFIG_CRYPTO=y
 #
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -1356,3 +1416,4 @@ CONFIG_ZLIB_INFLATE=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/blackfin/configs/TCM-BF518_defconfig b/arch/blackfin/configs/TCM-BF518_defconfig
new file mode 100644 (file)
index 0000000..4d31e2a
--- /dev/null
@@ -0,0 +1,1375 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32.3
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_BUG=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_BZIP2 is not set
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+CONFIG_EPOLL=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_FREEZER is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF512 is not set
+# CONFIG_BF514 is not set
+# CONFIG_BF516 is not set
+CONFIG_BF518=y
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF538 is not set
+# CONFIG_BF539 is not set
+# CONFIG_BF542_std is not set
+# CONFIG_BF542M is not set
+# CONFIG_BF544_std is not set
+# CONFIG_BF544M is not set
+# CONFIG_BF547_std is not set
+# CONFIG_BF547M is not set
+# CONFIG_BF548_std is not set
+# CONFIG_BF548M is not set
+# CONFIG_BF549_std is not set
+# CONFIG_BF549M is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_MIN=0
+CONFIG_BF_REV_MAX=2
+# CONFIG_BF_REV_0_0 is not set
+CONFIG_BF_REV_0_1=y
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_0_6 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF51x=y
+# CONFIG_BFIN518F_EZBRD is not set
+CONFIG_BFIN518F_TCM=y
+
+#
+# BF518 Specific Configuration
+#
+
+#
+# Alternative Multiplexing Scheme
+#
+# CONFIG_BF518_SPORT0_PORTF is not set
+CONFIG_BF518_SPORT0_PORTG=y
+CONFIG_BF518_SPORT0_TSCLK_PG10=y
+# CONFIG_BF518_SPORT0_TSCLK_PG14 is not set
+CONFIG_BF518_UART1_PORTF=y
+# CONFIG_BF518_UART1_PORTG is not set
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_DMA0_ERROR=7
+CONFIG_IRQ_DMAR0_BLK=7
+CONFIG_IRQ_DMAR1_BLK=7
+CONFIG_IRQ_DMAR0_OVR=7
+CONFIG_IRQ_DMAR1_OVR=7
+CONFIG_IRQ_PPI_ERROR=7
+CONFIG_IRQ_MAC_ERROR=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_PTP_ERROR=7
+CONFIG_IRQ_UART0_ERROR=7
+CONFIG_IRQ_UART1_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI0=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_OPTSEC=11
+CONFIG_IRQ_CNT=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_PORTH_INTA=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_PORTH_INTB=11
+CONFIG_IRQ_TIMER0=12
+CONFIG_IRQ_TIMER1=12
+CONFIG_IRQ_TIMER2=12
+CONFIG_IRQ_TIMER3=12
+CONFIG_IRQ_TIMER4=12
+CONFIG_IRQ_TIMER5=12
+CONFIG_IRQ_TIMER6=12
+CONFIG_IRQ_TIMER7=12
+CONFIG_IRQ_PORTG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_PORTF_INTA=13
+CONFIG_IRQ_PORTF_INTB=13
+CONFIG_IRQ_SPI0_ERROR=7
+CONFIG_IRQ_SPI1_ERROR=7
+CONFIG_IRQ_RSI_INT0=7
+CONFIG_IRQ_RSI_INT1=7
+CONFIG_IRQ_PWM_TRIP=10
+CONFIG_IRQ_PWM_SYNC=10
+CONFIG_IRQ_PTP_STAT=10
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=400000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+
+#
+# Clock event device
+#
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
+
+#
+# Clock souce
+#
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Misc
+#
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_APP_STACK_L1=y
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
+CONFIG_BFIN_GPTIMERS=m
+# CONFIG_DMA_UNCACHED_4M is not set
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_512K is not set
+# CONFIG_DMA_UNCACHED_256K is not set
+# CONFIG_DMA_UNCACHED_128K is not set
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_EXTMEM_ICACHEABLE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+CONFIG_BFIN_EXTMEM_DCACHEABLE=y
+CONFIG_BFIN_EXTMEM_WRITEBACK=y
+# CONFIG_BFIN_EXTMEM_WRITETHROUGH is not set
+
+#
+# Memory Protection Unit
+#
+# CONFIG_MPU is not set
+
+#
+# Asynchronous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B2
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+# CONFIG_BFIN_MAC_RMII is not set
+CONFIG_BFIN_MAC_USE_HWSTAMP=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_ADF702X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_PCF8574 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BFIN_SPI_ADC is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TWI_LCD is not set
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART1 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN_LOCK=y
+# CONFIG_SPI_BFIN_SPORT is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_DEBUG=y
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+CONFIG_MMC_SPI=y
+# CONFIG_SDH_BFIN is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_SIGMA is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_NOMMU_REGIONS is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_VERBOSE=y
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+# CONFIG_BFIN_ISRAM_SELF_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_TOMOYO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 57bc21a..8368951 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef BFIN_LQ035Q1_H
 #define BFIN_LQ035Q1_H
 
+/*
+ * LCD Modes
+ */
 #define LQ035_RL       (0 << 8)        /* Right -> Left Scan */
 #define LQ035_LR       (1 << 8)        /* Left -> Right Scan */
 #define LQ035_TB       (1 << 9)        /* Top -> Botton Scan */
 #define LQ035_NORM     (1 << 13)       /* Reversal */
 #define LQ035_REV      (0 << 13)       /* Reversal */
 
+/*
+ * PPI Modes
+ */
+
+#define USE_RGB565_16_BIT_PPI  1
+#define USE_RGB565_8_BIT_PPI   2
+#define USE_RGB888_8_BIT_PPI   3
+
 struct bfin_lq035q1fb_disp_info {
 
        unsigned        mode;
+       unsigned        ppi_mode;
        /* GPIOs */
        int             use_bl;
        unsigned        gpio_bl;
diff --git a/arch/blackfin/include/asm/bfin_can.h b/arch/blackfin/include/asm/bfin_can.h
new file mode 100644 (file)
index 0000000..eec0076
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * bfin_can.h - interface to Blackfin CANs
+ *
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_CAN_H__
+#define __ASM_BFIN_CAN_H__
+
+/*
+ * transmit and receive channels
+ */
+#define TRANSMIT_CHL            24
+#define RECEIVE_STD_CHL         0
+#define RECEIVE_EXT_CHL         4
+#define RECEIVE_RTR_CHL         8
+#define RECEIVE_EXT_RTR_CHL     12
+#define MAX_CHL_NUMBER          32
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin can registers layout
+ */
+struct bfin_can_mask_regs {
+       __BFP(aml);
+       __BFP(amh);
+};
+
+struct bfin_can_channel_regs {
+       u16 data[8];
+       __BFP(dlc);
+       __BFP(tsv);
+       __BFP(id0);
+       __BFP(id1);
+};
+
+struct bfin_can_regs {
+       /*
+        * global control and status registers
+        */
+       __BFP(mc1);           /* offset 0x00 */
+       __BFP(md1);           /* offset 0x04 */
+       __BFP(trs1);          /* offset 0x08 */
+       __BFP(trr1);          /* offset 0x0c */
+       __BFP(ta1);           /* offset 0x10 */
+       __BFP(aa1);           /* offset 0x14 */
+       __BFP(rmp1);          /* offset 0x18 */
+       __BFP(rml1);          /* offset 0x1c */
+       __BFP(mbtif1);        /* offset 0x20 */
+       __BFP(mbrif1);        /* offset 0x24 */
+       __BFP(mbim1);         /* offset 0x28 */
+       __BFP(rfh1);          /* offset 0x2c */
+       __BFP(opss1);         /* offset 0x30 */
+       u32 __pad1[3];
+       __BFP(mc2);           /* offset 0x40 */
+       __BFP(md2);           /* offset 0x44 */
+       __BFP(trs2);          /* offset 0x48 */
+       __BFP(trr2);          /* offset 0x4c */
+       __BFP(ta2);           /* offset 0x50 */
+       __BFP(aa2);           /* offset 0x54 */
+       __BFP(rmp2);          /* offset 0x58 */
+       __BFP(rml2);          /* offset 0x5c */
+       __BFP(mbtif2);        /* offset 0x60 */
+       __BFP(mbrif2);        /* offset 0x64 */
+       __BFP(mbim2);         /* offset 0x68 */
+       __BFP(rfh2);          /* offset 0x6c */
+       __BFP(opss2);         /* offset 0x70 */
+       u32 __pad2[3];
+       __BFP(clock);         /* offset 0x80 */
+       __BFP(timing);        /* offset 0x84 */
+       __BFP(debug);         /* offset 0x88 */
+       __BFP(status);        /* offset 0x8c */
+       __BFP(cec);           /* offset 0x90 */
+       __BFP(gis);           /* offset 0x94 */
+       __BFP(gim);           /* offset 0x98 */
+       __BFP(gif);           /* offset 0x9c */
+       __BFP(control);       /* offset 0xa0 */
+       __BFP(intr);          /* offset 0xa4 */
+       u32 __pad3[1];
+       __BFP(mbtd);          /* offset 0xac */
+       __BFP(ewr);           /* offset 0xb0 */
+       __BFP(esr);           /* offset 0xb4 */
+       u32 __pad4[2];
+       __BFP(ucreg);         /* offset 0xc0 */
+       __BFP(uccnt);         /* offset 0xc4 */
+       __BFP(ucrc);          /* offset 0xc8 */
+       __BFP(uccnf);         /* offset 0xcc */
+       u32 __pad5[12];
+
+       /*
+        * channel(mailbox) mask and message registers
+        */
+       struct bfin_can_mask_regs msk[MAX_CHL_NUMBER];    /* offset 0x100 */
+       struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */
+};
+
+#undef __BFP
+
+/* CAN_CONTROL Masks */
+#define SRS                    0x0001  /* Software Reset */
+#define DNM                    0x0002  /* Device Net Mode */
+#define ABO                    0x0004  /* Auto-Bus On Enable */
+#define TXPRIO         0x0008  /* TX Priority (Priority/Mailbox*) */
+#define WBA                    0x0010  /* Wake-Up On CAN Bus Activity Enable */
+#define SMR                    0x0020  /* Sleep Mode Request */
+#define CSR                    0x0040  /* CAN Suspend Mode Request */
+#define CCR                    0x0080  /* CAN Configuration Mode Request */
+
+/* CAN_STATUS Masks */
+#define WT                     0x0001  /* TX Warning Flag */
+#define WR                     0x0002  /* RX Warning Flag */
+#define EP                     0x0004  /* Error Passive Mode */
+#define EBO                    0x0008  /* Error Bus Off Mode */
+#define SMA                    0x0020  /* Sleep Mode Acknowledge */
+#define CSA                    0x0040  /* Suspend Mode Acknowledge */
+#define CCA                    0x0080  /* Configuration Mode Acknowledge */
+#define MBPTR          0x1F00  /* Mailbox Pointer */
+#define TRM                    0x4000  /* Transmit Mode */
+#define REC                    0x8000  /* Receive Mode */
+
+/* CAN_CLOCK Masks */
+#define BRP                    0x03FF  /* Bit-Rate Pre-Scaler */
+
+/* CAN_TIMING Masks */
+#define TSEG1          0x000F  /* Time Segment 1 */
+#define TSEG2          0x0070  /* Time Segment 2 */
+#define SAM                    0x0080  /* Sampling */
+#define SJW                    0x0300  /* Synchronization Jump Width */
+
+/* CAN_DEBUG Masks */
+#define DEC                    0x0001  /* Disable CAN Error Counters */
+#define DRI                    0x0002  /* Disable CAN RX Input */
+#define DTO                    0x0004  /* Disable CAN TX Output */
+#define DIL                    0x0008  /* Disable CAN Internal Loop */
+#define MAA                    0x0010  /* Mode Auto-Acknowledge Enable */
+#define MRB                    0x0020  /* Mode Read Back Enable */
+#define CDE                    0x8000  /* CAN Debug Enable */
+
+/* CAN_CEC Masks */
+#define RXECNT         0x00FF  /* Receive Error Counter */
+#define TXECNT         0xFF00  /* Transmit Error Counter */
+
+/* CAN_INTR Masks */
+#define MBRIRQ 0x0001  /* Mailbox Receive Interrupt */
+#define MBTIRQ 0x0002  /* Mailbox Transmit Interrupt */
+#define GIRQ           0x0004  /* Global Interrupt */
+#define SMACK          0x0008  /* Sleep Mode Acknowledge */
+#define CANTX          0x0040  /* CAN TX Bus Value */
+#define CANRX          0x0080  /* CAN RX Bus Value */
+
+/* CAN_MBxx_ID1 and CAN_MBxx_ID0 Masks */
+#define DFC                    0xFFFF  /* Data Filtering Code (If Enabled) (ID0) */
+#define EXTID_LO       0xFFFF  /* Lower 16 Bits of Extended Identifier (ID0) */
+#define EXTID_HI       0x0003  /* Upper 2 Bits of Extended Identifier (ID1) */
+#define BASEID         0x1FFC  /* Base Identifier */
+#define IDE                    0x2000  /* Identifier Extension */
+#define RTR                    0x4000  /* Remote Frame Transmission Request */
+#define AME                    0x8000  /* Acceptance Mask Enable */
+
+/* CAN_MBxx_TIMESTAMP Masks */
+#define TSV                    0xFFFF  /* Timestamp */
+
+/* CAN_MBxx_LENGTH Masks */
+#define DLC                    0x000F  /* Data Length Code */
+
+/* CAN_AMxxH and CAN_AMxxL Masks */
+#define DFM                    0xFFFF  /* Data Field Mask (If Enabled) (CAN_AMxxL) */
+#define EXTID_LO       0xFFFF  /* Lower 16 Bits of Extended Identifier (CAN_AMxxL) */
+#define EXTID_HI       0x0003  /* Upper 2 Bits of Extended Identifier (CAN_AMxxH) */
+#define BASEID         0x1FFC  /* Base Identifier */
+#define AMIDE          0x2000  /* Acceptance Mask ID Extension Enable */
+#define FMD                    0x4000  /* Full Mask Data Field Enable */
+#define FDF                    0x8000  /* Filter On Data Field Enable */
+
+/* CAN_MC1 Masks */
+#define MC0                    0x0001  /* Enable Mailbox 0 */
+#define MC1                    0x0002  /* Enable Mailbox 1 */
+#define MC2                    0x0004  /* Enable Mailbox 2 */
+#define MC3                    0x0008  /* Enable Mailbox 3 */
+#define MC4                    0x0010  /* Enable Mailbox 4 */
+#define MC5                    0x0020  /* Enable Mailbox 5 */
+#define MC6                    0x0040  /* Enable Mailbox 6 */
+#define MC7                    0x0080  /* Enable Mailbox 7 */
+#define MC8                    0x0100  /* Enable Mailbox 8 */
+#define MC9                    0x0200  /* Enable Mailbox 9 */
+#define MC10           0x0400  /* Enable Mailbox 10 */
+#define MC11           0x0800  /* Enable Mailbox 11 */
+#define MC12           0x1000  /* Enable Mailbox 12 */
+#define MC13           0x2000  /* Enable Mailbox 13 */
+#define MC14           0x4000  /* Enable Mailbox 14 */
+#define MC15           0x8000  /* Enable Mailbox 15 */
+
+/* CAN_MC2 Masks */
+#define MC16           0x0001  /* Enable Mailbox 16 */
+#define MC17           0x0002  /* Enable Mailbox 17 */
+#define MC18           0x0004  /* Enable Mailbox 18 */
+#define MC19           0x0008  /* Enable Mailbox 19 */
+#define MC20           0x0010  /* Enable Mailbox 20 */
+#define MC21           0x0020  /* Enable Mailbox 21 */
+#define MC22           0x0040  /* Enable Mailbox 22 */
+#define MC23           0x0080  /* Enable Mailbox 23 */
+#define MC24           0x0100  /* Enable Mailbox 24 */
+#define MC25           0x0200  /* Enable Mailbox 25 */
+#define MC26           0x0400  /* Enable Mailbox 26 */
+#define MC27           0x0800  /* Enable Mailbox 27 */
+#define MC28           0x1000  /* Enable Mailbox 28 */
+#define MC29           0x2000  /* Enable Mailbox 29 */
+#define MC30           0x4000  /* Enable Mailbox 30 */
+#define MC31           0x8000  /* Enable Mailbox 31 */
+
+/* CAN_MD1 Masks */
+#define MD0                    0x0001  /* Enable Mailbox 0 For Receive */
+#define MD1                    0x0002  /* Enable Mailbox 1 For Receive */
+#define MD2                    0x0004  /* Enable Mailbox 2 For Receive */
+#define MD3                    0x0008  /* Enable Mailbox 3 For Receive */
+#define MD4                    0x0010  /* Enable Mailbox 4 For Receive */
+#define MD5                    0x0020  /* Enable Mailbox 5 For Receive */
+#define MD6                    0x0040  /* Enable Mailbox 6 For Receive */
+#define MD7                    0x0080  /* Enable Mailbox 7 For Receive */
+#define MD8                    0x0100  /* Enable Mailbox 8 For Receive */
+#define MD9                    0x0200  /* Enable Mailbox 9 For Receive */
+#define MD10           0x0400  /* Enable Mailbox 10 For Receive */
+#define MD11           0x0800  /* Enable Mailbox 11 For Receive */
+#define MD12           0x1000  /* Enable Mailbox 12 For Receive */
+#define MD13           0x2000  /* Enable Mailbox 13 For Receive */
+#define MD14           0x4000  /* Enable Mailbox 14 For Receive */
+#define MD15           0x8000  /* Enable Mailbox 15 For Receive */
+
+/* CAN_MD2 Masks */
+#define MD16           0x0001  /* Enable Mailbox 16 For Receive */
+#define MD17           0x0002  /* Enable Mailbox 17 For Receive */
+#define MD18           0x0004  /* Enable Mailbox 18 For Receive */
+#define MD19           0x0008  /* Enable Mailbox 19 For Receive */
+#define MD20           0x0010  /* Enable Mailbox 20 For Receive */
+#define MD21           0x0020  /* Enable Mailbox 21 For Receive */
+#define MD22           0x0040  /* Enable Mailbox 22 For Receive */
+#define MD23           0x0080  /* Enable Mailbox 23 For Receive */
+#define MD24           0x0100  /* Enable Mailbox 24 For Receive */
+#define MD25           0x0200  /* Enable Mailbox 25 For Receive */
+#define MD26           0x0400  /* Enable Mailbox 26 For Receive */
+#define MD27           0x0800  /* Enable Mailbox 27 For Receive */
+#define MD28           0x1000  /* Enable Mailbox 28 For Receive */
+#define MD29           0x2000  /* Enable Mailbox 29 For Receive */
+#define MD30           0x4000  /* Enable Mailbox 30 For Receive */
+#define MD31           0x8000  /* Enable Mailbox 31 For Receive */
+
+/* CAN_RMP1 Masks */
+#define RMP0           0x0001  /* RX Message Pending In Mailbox 0 */
+#define RMP1           0x0002  /* RX Message Pending In Mailbox 1 */
+#define RMP2           0x0004  /* RX Message Pending In Mailbox 2 */
+#define RMP3           0x0008  /* RX Message Pending In Mailbox 3 */
+#define RMP4           0x0010  /* RX Message Pending In Mailbox 4 */
+#define RMP5           0x0020  /* RX Message Pending In Mailbox 5 */
+#define RMP6           0x0040  /* RX Message Pending In Mailbox 6 */
+#define RMP7           0x0080  /* RX Message Pending In Mailbox 7 */
+#define RMP8           0x0100  /* RX Message Pending In Mailbox 8 */
+#define RMP9           0x0200  /* RX Message Pending In Mailbox 9 */
+#define RMP10          0x0400  /* RX Message Pending In Mailbox 10 */
+#define RMP11          0x0800  /* RX Message Pending In Mailbox 11 */
+#define RMP12          0x1000  /* RX Message Pending In Mailbox 12 */
+#define RMP13          0x2000  /* RX Message Pending In Mailbox 13 */
+#define RMP14          0x4000  /* RX Message Pending In Mailbox 14 */
+#define RMP15          0x8000  /* RX Message Pending In Mailbox 15 */
+
+/* CAN_RMP2 Masks */
+#define RMP16          0x0001  /* RX Message Pending In Mailbox 16 */
+#define RMP17          0x0002  /* RX Message Pending In Mailbox 17 */
+#define RMP18          0x0004  /* RX Message Pending In Mailbox 18 */
+#define RMP19          0x0008  /* RX Message Pending In Mailbox 19 */
+#define RMP20          0x0010  /* RX Message Pending In Mailbox 20 */
+#define RMP21          0x0020  /* RX Message Pending In Mailbox 21 */
+#define RMP22          0x0040  /* RX Message Pending In Mailbox 22 */
+#define RMP23          0x0080  /* RX Message Pending In Mailbox 23 */
+#define RMP24          0x0100  /* RX Message Pending In Mailbox 24 */
+#define RMP25          0x0200  /* RX Message Pending In Mailbox 25 */
+#define RMP26          0x0400  /* RX Message Pending In Mailbox 26 */
+#define RMP27          0x0800  /* RX Message Pending In Mailbox 27 */
+#define RMP28          0x1000  /* RX Message Pending In Mailbox 28 */
+#define RMP29          0x2000  /* RX Message Pending In Mailbox 29 */
+#define RMP30          0x4000  /* RX Message Pending In Mailbox 30 */
+#define RMP31          0x8000  /* RX Message Pending In Mailbox 31 */
+
+/* CAN_RML1 Masks */
+#define RML0           0x0001  /* RX Message Lost In Mailbox 0 */
+#define RML1           0x0002  /* RX Message Lost In Mailbox 1 */
+#define RML2           0x0004  /* RX Message Lost In Mailbox 2 */
+#define RML3           0x0008  /* RX Message Lost In Mailbox 3 */
+#define RML4           0x0010  /* RX Message Lost In Mailbox 4 */
+#define RML5           0x0020  /* RX Message Lost In Mailbox 5 */
+#define RML6           0x0040  /* RX Message Lost In Mailbox 6 */
+#define RML7           0x0080  /* RX Message Lost In Mailbox 7 */
+#define RML8           0x0100  /* RX Message Lost In Mailbox 8 */
+#define RML9           0x0200  /* RX Message Lost In Mailbox 9 */
+#define RML10          0x0400  /* RX Message Lost In Mailbox 10 */
+#define RML11          0x0800  /* RX Message Lost In Mailbox 11 */
+#define RML12          0x1000  /* RX Message Lost In Mailbox 12 */
+#define RML13          0x2000  /* RX Message Lost In Mailbox 13 */
+#define RML14          0x4000  /* RX Message Lost In Mailbox 14 */
+#define RML15          0x8000  /* RX Message Lost In Mailbox 15 */
+
+/* CAN_RML2 Masks */
+#define RML16          0x0001  /* RX Message Lost In Mailbox 16 */
+#define RML17          0x0002  /* RX Message Lost In Mailbox 17 */
+#define RML18          0x0004  /* RX Message Lost In Mailbox 18 */
+#define RML19          0x0008  /* RX Message Lost In Mailbox 19 */
+#define RML20          0x0010  /* RX Message Lost In Mailbox 20 */
+#define RML21          0x0020  /* RX Message Lost In Mailbox 21 */
+#define RML22          0x0040  /* RX Message Lost In Mailbox 22 */
+#define RML23          0x0080  /* RX Message Lost In Mailbox 23 */
+#define RML24          0x0100  /* RX Message Lost In Mailbox 24 */
+#define RML25          0x0200  /* RX Message Lost In Mailbox 25 */
+#define RML26          0x0400  /* RX Message Lost In Mailbox 26 */
+#define RML27          0x0800  /* RX Message Lost In Mailbox 27 */
+#define RML28          0x1000  /* RX Message Lost In Mailbox 28 */
+#define RML29          0x2000  /* RX Message Lost In Mailbox 29 */
+#define RML30          0x4000  /* RX Message Lost In Mailbox 30 */
+#define RML31          0x8000  /* RX Message Lost In Mailbox 31 */
+
+/* CAN_OPSS1 Masks */
+#define OPSS0          0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 0 */
+#define OPSS1          0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 1 */
+#define OPSS2          0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 2 */
+#define OPSS3          0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 3 */
+#define OPSS4          0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 4 */
+#define OPSS5          0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 5 */
+#define OPSS6          0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 6 */
+#define OPSS7          0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 7 */
+#define OPSS8          0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 8 */
+#define OPSS9          0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 9 */
+#define OPSS10         0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 10 */
+#define OPSS11         0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 11 */
+#define OPSS12         0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 12 */
+#define OPSS13         0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 13 */
+#define OPSS14         0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 14 */
+#define OPSS15         0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 15 */
+
+/* CAN_OPSS2 Masks */
+#define OPSS16         0x0001  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 16 */
+#define OPSS17         0x0002  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 17 */
+#define OPSS18         0x0004  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 18 */
+#define OPSS19         0x0008  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 19 */
+#define OPSS20         0x0010  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 20 */
+#define OPSS21         0x0020  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 21 */
+#define OPSS22         0x0040  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 22 */
+#define OPSS23         0x0080  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 23 */
+#define OPSS24         0x0100  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 24 */
+#define OPSS25         0x0200  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 25 */
+#define OPSS26         0x0400  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 26 */
+#define OPSS27         0x0800  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 27 */
+#define OPSS28         0x1000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 28 */
+#define OPSS29         0x2000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 29 */
+#define OPSS30         0x4000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 30 */
+#define OPSS31         0x8000  /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 31 */
+
+/* CAN_TRR1 Masks */
+#define TRR0           0x0001  /* Deny But Don't Lock Access To Mailbox 0 */
+#define TRR1           0x0002  /* Deny But Don't Lock Access To Mailbox 1 */
+#define TRR2           0x0004  /* Deny But Don't Lock Access To Mailbox 2 */
+#define TRR3           0x0008  /* Deny But Don't Lock Access To Mailbox 3 */
+#define TRR4           0x0010  /* Deny But Don't Lock Access To Mailbox 4 */
+#define TRR5           0x0020  /* Deny But Don't Lock Access To Mailbox 5 */
+#define TRR6           0x0040  /* Deny But Don't Lock Access To Mailbox 6 */
+#define TRR7           0x0080  /* Deny But Don't Lock Access To Mailbox 7 */
+#define TRR8           0x0100  /* Deny But Don't Lock Access To Mailbox 8 */
+#define TRR9           0x0200  /* Deny But Don't Lock Access To Mailbox 9 */
+#define TRR10          0x0400  /* Deny But Don't Lock Access To Mailbox 10 */
+#define TRR11          0x0800  /* Deny But Don't Lock Access To Mailbox 11 */
+#define TRR12          0x1000  /* Deny But Don't Lock Access To Mailbox 12 */
+#define TRR13          0x2000  /* Deny But Don't Lock Access To Mailbox 13 */
+#define TRR14          0x4000  /* Deny But Don't Lock Access To Mailbox 14 */
+#define TRR15          0x8000  /* Deny But Don't Lock Access To Mailbox 15 */
+
+/* CAN_TRR2 Masks */
+#define TRR16          0x0001  /* Deny But Don't Lock Access To Mailbox 16 */
+#define TRR17          0x0002  /* Deny But Don't Lock Access To Mailbox 17 */
+#define TRR18          0x0004  /* Deny But Don't Lock Access To Mailbox 18 */
+#define TRR19          0x0008  /* Deny But Don't Lock Access To Mailbox 19 */
+#define TRR20          0x0010  /* Deny But Don't Lock Access To Mailbox 20 */
+#define TRR21          0x0020  /* Deny But Don't Lock Access To Mailbox 21 */
+#define TRR22          0x0040  /* Deny But Don't Lock Access To Mailbox 22 */
+#define TRR23          0x0080  /* Deny But Don't Lock Access To Mailbox 23 */
+#define TRR24          0x0100  /* Deny But Don't Lock Access To Mailbox 24 */
+#define TRR25          0x0200  /* Deny But Don't Lock Access To Mailbox 25 */
+#define TRR26          0x0400  /* Deny But Don't Lock Access To Mailbox 26 */
+#define TRR27          0x0800  /* Deny But Don't Lock Access To Mailbox 27 */
+#define TRR28          0x1000  /* Deny But Don't Lock Access To Mailbox 28 */
+#define TRR29          0x2000  /* Deny But Don't Lock Access To Mailbox 29 */
+#define TRR30          0x4000  /* Deny But Don't Lock Access To Mailbox 30 */
+#define TRR31          0x8000  /* Deny But Don't Lock Access To Mailbox 31 */
+
+/* CAN_TRS1 Masks */
+#define TRS0           0x0001  /* Remote Frame Request For Mailbox 0 */
+#define TRS1           0x0002  /* Remote Frame Request For Mailbox 1 */
+#define TRS2           0x0004  /* Remote Frame Request For Mailbox 2 */
+#define TRS3           0x0008  /* Remote Frame Request For Mailbox 3 */
+#define TRS4           0x0010  /* Remote Frame Request For Mailbox 4 */
+#define TRS5           0x0020  /* Remote Frame Request For Mailbox 5 */
+#define TRS6           0x0040  /* Remote Frame Request For Mailbox 6 */
+#define TRS7           0x0080  /* Remote Frame Request For Mailbox 7 */
+#define TRS8           0x0100  /* Remote Frame Request For Mailbox 8 */
+#define TRS9           0x0200  /* Remote Frame Request For Mailbox 9 */
+#define TRS10          0x0400  /* Remote Frame Request For Mailbox 10 */
+#define TRS11          0x0800  /* Remote Frame Request For Mailbox 11 */
+#define TRS12          0x1000  /* Remote Frame Request For Mailbox 12 */
+#define TRS13          0x2000  /* Remote Frame Request For Mailbox 13 */
+#define TRS14          0x4000  /* Remote Frame Request For Mailbox 14 */
+#define TRS15          0x8000  /* Remote Frame Request For Mailbox 15 */
+
+/* CAN_TRS2 Masks */
+#define TRS16          0x0001  /* Remote Frame Request For Mailbox 16 */
+#define TRS17          0x0002  /* Remote Frame Request For Mailbox 17 */
+#define TRS18          0x0004  /* Remote Frame Request For Mailbox 18 */
+#define TRS19          0x0008  /* Remote Frame Request For Mailbox 19 */
+#define TRS20          0x0010  /* Remote Frame Request For Mailbox 20 */
+#define TRS21          0x0020  /* Remote Frame Request For Mailbox 21 */
+#define TRS22          0x0040  /* Remote Frame Request For Mailbox 22 */
+#define TRS23          0x0080  /* Remote Frame Request For Mailbox 23 */
+#define TRS24          0x0100  /* Remote Frame Request For Mailbox 24 */
+#define TRS25          0x0200  /* Remote Frame Request For Mailbox 25 */
+#define TRS26          0x0400  /* Remote Frame Request For Mailbox 26 */
+#define TRS27          0x0800  /* Remote Frame Request For Mailbox 27 */
+#define TRS28          0x1000  /* Remote Frame Request For Mailbox 28 */
+#define TRS29          0x2000  /* Remote Frame Request For Mailbox 29 */
+#define TRS30          0x4000  /* Remote Frame Request For Mailbox 30 */
+#define TRS31          0x8000  /* Remote Frame Request For Mailbox 31 */
+
+/* CAN_AA1 Masks */
+#define AA0                    0x0001  /* Aborted Message In Mailbox 0 */
+#define AA1                    0x0002  /* Aborted Message In Mailbox 1 */
+#define AA2                    0x0004  /* Aborted Message In Mailbox 2 */
+#define AA3                    0x0008  /* Aborted Message In Mailbox 3 */
+#define AA4                    0x0010  /* Aborted Message In Mailbox 4 */
+#define AA5                    0x0020  /* Aborted Message In Mailbox 5 */
+#define AA6                    0x0040  /* Aborted Message In Mailbox 6 */
+#define AA7                    0x0080  /* Aborted Message In Mailbox 7 */
+#define AA8                    0x0100  /* Aborted Message In Mailbox 8 */
+#define AA9                    0x0200  /* Aborted Message In Mailbox 9 */
+#define AA10           0x0400  /* Aborted Message In Mailbox 10 */
+#define AA11           0x0800  /* Aborted Message In Mailbox 11 */
+#define AA12           0x1000  /* Aborted Message In Mailbox 12 */
+#define AA13           0x2000  /* Aborted Message In Mailbox 13 */
+#define AA14           0x4000  /* Aborted Message In Mailbox 14 */
+#define AA15           0x8000  /* Aborted Message In Mailbox 15 */
+
+/* CAN_AA2 Masks */
+#define AA16           0x0001  /* Aborted Message In Mailbox 16 */
+#define AA17           0x0002  /* Aborted Message In Mailbox 17 */
+#define AA18           0x0004  /* Aborted Message In Mailbox 18 */
+#define AA19           0x0008  /* Aborted Message In Mailbox 19 */
+#define AA20           0x0010  /* Aborted Message In Mailbox 20 */
+#define AA21           0x0020  /* Aborted Message In Mailbox 21 */
+#define AA22           0x0040  /* Aborted Message In Mailbox 22 */
+#define AA23           0x0080  /* Aborted Message In Mailbox 23 */
+#define AA24           0x0100  /* Aborted Message In Mailbox 24 */
+#define AA25           0x0200  /* Aborted Message In Mailbox 25 */
+#define AA26           0x0400  /* Aborted Message In Mailbox 26 */
+#define AA27           0x0800  /* Aborted Message In Mailbox 27 */
+#define AA28           0x1000  /* Aborted Message In Mailbox 28 */
+#define AA29           0x2000  /* Aborted Message In Mailbox 29 */
+#define AA30           0x4000  /* Aborted Message In Mailbox 30 */
+#define AA31           0x8000  /* Aborted Message In Mailbox 31 */
+
+/* CAN_TA1 Masks */
+#define TA0                    0x0001  /* Transmit Successful From Mailbox 0 */
+#define TA1                    0x0002  /* Transmit Successful From Mailbox 1 */
+#define TA2                    0x0004  /* Transmit Successful From Mailbox 2 */
+#define TA3                    0x0008  /* Transmit Successful From Mailbox 3 */
+#define TA4                    0x0010  /* Transmit Successful From Mailbox 4 */
+#define TA5                    0x0020  /* Transmit Successful From Mailbox 5 */
+#define TA6                    0x0040  /* Transmit Successful From Mailbox 6 */
+#define TA7                    0x0080  /* Transmit Successful From Mailbox 7 */
+#define TA8                    0x0100  /* Transmit Successful From Mailbox 8 */
+#define TA9                    0x0200  /* Transmit Successful From Mailbox 9 */
+#define TA10           0x0400  /* Transmit Successful From Mailbox 10 */
+#define TA11           0x0800  /* Transmit Successful From Mailbox 11 */
+#define TA12           0x1000  /* Transmit Successful From Mailbox 12 */
+#define TA13           0x2000  /* Transmit Successful From Mailbox 13 */
+#define TA14           0x4000  /* Transmit Successful From Mailbox 14 */
+#define TA15           0x8000  /* Transmit Successful From Mailbox 15 */
+
+/* CAN_TA2 Masks */
+#define TA16           0x0001  /* Transmit Successful From Mailbox 16 */
+#define TA17           0x0002  /* Transmit Successful From Mailbox 17 */
+#define TA18           0x0004  /* Transmit Successful From Mailbox 18 */
+#define TA19           0x0008  /* Transmit Successful From Mailbox 19 */
+#define TA20           0x0010  /* Transmit Successful From Mailbox 20 */
+#define TA21           0x0020  /* Transmit Successful From Mailbox 21 */
+#define TA22           0x0040  /* Transmit Successful From Mailbox 22 */
+#define TA23           0x0080  /* Transmit Successful From Mailbox 23 */
+#define TA24           0x0100  /* Transmit Successful From Mailbox 24 */
+#define TA25           0x0200  /* Transmit Successful From Mailbox 25 */
+#define TA26           0x0400  /* Transmit Successful From Mailbox 26 */
+#define TA27           0x0800  /* Transmit Successful From Mailbox 27 */
+#define TA28           0x1000  /* Transmit Successful From Mailbox 28 */
+#define TA29           0x2000  /* Transmit Successful From Mailbox 29 */
+#define TA30           0x4000  /* Transmit Successful From Mailbox 30 */
+#define TA31           0x8000  /* Transmit Successful From Mailbox 31 */
+
+/* CAN_MBTD Masks */
+#define TDPTR          0x001F  /* Mailbox To Temporarily Disable */
+#define TDA                    0x0040  /* Temporary Disable Acknowledge */
+#define TDR                    0x0080  /* Temporary Disable Request */
+
+/* CAN_RFH1 Masks */
+#define RFH0           0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 0 */
+#define RFH1           0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 1 */
+#define RFH2           0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 2 */
+#define RFH3           0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 3 */
+#define RFH4           0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 4 */
+#define RFH5           0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 5 */
+#define RFH6           0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 6 */
+#define RFH7           0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 7 */
+#define RFH8           0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 8 */
+#define RFH9           0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 9 */
+#define RFH10          0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 10 */
+#define RFH11          0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 11 */
+#define RFH12          0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 12 */
+#define RFH13          0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 13 */
+#define RFH14          0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 14 */
+#define RFH15          0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 15 */
+
+/* CAN_RFH2 Masks */
+#define RFH16          0x0001  /* Enable Automatic Remote Frame Handling For Mailbox 16 */
+#define RFH17          0x0002  /* Enable Automatic Remote Frame Handling For Mailbox 17 */
+#define RFH18          0x0004  /* Enable Automatic Remote Frame Handling For Mailbox 18 */
+#define RFH19          0x0008  /* Enable Automatic Remote Frame Handling For Mailbox 19 */
+#define RFH20          0x0010  /* Enable Automatic Remote Frame Handling For Mailbox 20 */
+#define RFH21          0x0020  /* Enable Automatic Remote Frame Handling For Mailbox 21 */
+#define RFH22          0x0040  /* Enable Automatic Remote Frame Handling For Mailbox 22 */
+#define RFH23          0x0080  /* Enable Automatic Remote Frame Handling For Mailbox 23 */
+#define RFH24          0x0100  /* Enable Automatic Remote Frame Handling For Mailbox 24 */
+#define RFH25          0x0200  /* Enable Automatic Remote Frame Handling For Mailbox 25 */
+#define RFH26          0x0400  /* Enable Automatic Remote Frame Handling For Mailbox 26 */
+#define RFH27          0x0800  /* Enable Automatic Remote Frame Handling For Mailbox 27 */
+#define RFH28          0x1000  /* Enable Automatic Remote Frame Handling For Mailbox 28 */
+#define RFH29          0x2000  /* Enable Automatic Remote Frame Handling For Mailbox 29 */
+#define RFH30          0x4000  /* Enable Automatic Remote Frame Handling For Mailbox 30 */
+#define RFH31          0x8000  /* Enable Automatic Remote Frame Handling For Mailbox 31 */
+
+/* CAN_MBTIF1 Masks */
+#define MBTIF0         0x0001  /* TX Interrupt Active In Mailbox 0 */
+#define MBTIF1         0x0002  /* TX Interrupt Active In Mailbox 1 */
+#define MBTIF2         0x0004  /* TX Interrupt Active In Mailbox 2 */
+#define MBTIF3         0x0008  /* TX Interrupt Active In Mailbox 3 */
+#define MBTIF4         0x0010  /* TX Interrupt Active In Mailbox 4 */
+#define MBTIF5         0x0020  /* TX Interrupt Active In Mailbox 5 */
+#define MBTIF6         0x0040  /* TX Interrupt Active In Mailbox 6 */
+#define MBTIF7         0x0080  /* TX Interrupt Active In Mailbox 7 */
+#define MBTIF8         0x0100  /* TX Interrupt Active In Mailbox 8 */
+#define MBTIF9         0x0200  /* TX Interrupt Active In Mailbox 9 */
+#define MBTIF10                0x0400  /* TX Interrupt Active In Mailbox 10 */
+#define MBTIF11                0x0800  /* TX Interrupt Active In Mailbox 11 */
+#define MBTIF12                0x1000  /* TX Interrupt Active In Mailbox 12 */
+#define MBTIF13                0x2000  /* TX Interrupt Active In Mailbox 13 */
+#define MBTIF14                0x4000  /* TX Interrupt Active In Mailbox 14 */
+#define MBTIF15                0x8000  /* TX Interrupt Active In Mailbox 15 */
+
+/* CAN_MBTIF2 Masks */
+#define MBTIF16                0x0001  /* TX Interrupt Active In Mailbox 16 */
+#define MBTIF17                0x0002  /* TX Interrupt Active In Mailbox 17 */
+#define MBTIF18                0x0004  /* TX Interrupt Active In Mailbox 18 */
+#define MBTIF19                0x0008  /* TX Interrupt Active In Mailbox 19 */
+#define MBTIF20                0x0010  /* TX Interrupt Active In Mailbox 20 */
+#define MBTIF21                0x0020  /* TX Interrupt Active In Mailbox 21 */
+#define MBTIF22                0x0040  /* TX Interrupt Active In Mailbox 22 */
+#define MBTIF23                0x0080  /* TX Interrupt Active In Mailbox 23 */
+#define MBTIF24                0x0100  /* TX Interrupt Active In Mailbox 24 */
+#define MBTIF25                0x0200  /* TX Interrupt Active In Mailbox 25 */
+#define MBTIF26                0x0400  /* TX Interrupt Active In Mailbox 26 */
+#define MBTIF27                0x0800  /* TX Interrupt Active In Mailbox 27 */
+#define MBTIF28                0x1000  /* TX Interrupt Active In Mailbox 28 */
+#define MBTIF29                0x2000  /* TX Interrupt Active In Mailbox 29 */
+#define MBTIF30                0x4000  /* TX Interrupt Active In Mailbox 30 */
+#define MBTIF31                0x8000  /* TX Interrupt Active In Mailbox 31 */
+
+/* CAN_MBRIF1 Masks */
+#define MBRIF0         0x0001  /* RX Interrupt Active In Mailbox 0 */
+#define MBRIF1         0x0002  /* RX Interrupt Active In Mailbox 1 */
+#define MBRIF2         0x0004  /* RX Interrupt Active In Mailbox 2 */
+#define MBRIF3         0x0008  /* RX Interrupt Active In Mailbox 3 */
+#define MBRIF4         0x0010  /* RX Interrupt Active In Mailbox 4 */
+#define MBRIF5         0x0020  /* RX Interrupt Active In Mailbox 5 */
+#define MBRIF6         0x0040  /* RX Interrupt Active In Mailbox 6 */
+#define MBRIF7         0x0080  /* RX Interrupt Active In Mailbox 7 */
+#define MBRIF8         0x0100  /* RX Interrupt Active In Mailbox 8 */
+#define MBRIF9         0x0200  /* RX Interrupt Active In Mailbox 9 */
+#define MBRIF10                0x0400  /* RX Interrupt Active In Mailbox 10 */
+#define MBRIF11                0x0800  /* RX Interrupt Active In Mailbox 11 */
+#define MBRIF12                0x1000  /* RX Interrupt Active In Mailbox 12 */
+#define MBRIF13                0x2000  /* RX Interrupt Active In Mailbox 13 */
+#define MBRIF14                0x4000  /* RX Interrupt Active In Mailbox 14 */
+#define MBRIF15                0x8000  /* RX Interrupt Active In Mailbox 15 */
+
+/* CAN_MBRIF2 Masks */
+#define MBRIF16                0x0001  /* RX Interrupt Active In Mailbox 16 */
+#define MBRIF17                0x0002  /* RX Interrupt Active In Mailbox 17 */
+#define MBRIF18                0x0004  /* RX Interrupt Active In Mailbox 18 */
+#define MBRIF19                0x0008  /* RX Interrupt Active In Mailbox 19 */
+#define MBRIF20                0x0010  /* RX Interrupt Active In Mailbox 20 */
+#define MBRIF21                0x0020  /* RX Interrupt Active In Mailbox 21 */
+#define MBRIF22                0x0040  /* RX Interrupt Active In Mailbox 22 */
+#define MBRIF23                0x0080  /* RX Interrupt Active In Mailbox 23 */
+#define MBRIF24                0x0100  /* RX Interrupt Active In Mailbox 24 */
+#define MBRIF25                0x0200  /* RX Interrupt Active In Mailbox 25 */
+#define MBRIF26                0x0400  /* RX Interrupt Active In Mailbox 26 */
+#define MBRIF27                0x0800  /* RX Interrupt Active In Mailbox 27 */
+#define MBRIF28                0x1000  /* RX Interrupt Active In Mailbox 28 */
+#define MBRIF29                0x2000  /* RX Interrupt Active In Mailbox 29 */
+#define MBRIF30                0x4000  /* RX Interrupt Active In Mailbox 30 */
+#define MBRIF31                0x8000  /* RX Interrupt Active In Mailbox 31 */
+
+/* CAN_MBIM1 Masks */
+#define MBIM0          0x0001  /* Enable Interrupt For Mailbox 0 */
+#define MBIM1          0x0002  /* Enable Interrupt For Mailbox 1 */
+#define MBIM2          0x0004  /* Enable Interrupt For Mailbox 2 */
+#define MBIM3          0x0008  /* Enable Interrupt For Mailbox 3 */
+#define MBIM4          0x0010  /* Enable Interrupt For Mailbox 4 */
+#define MBIM5          0x0020  /* Enable Interrupt For Mailbox 5 */
+#define MBIM6          0x0040  /* Enable Interrupt For Mailbox 6 */
+#define MBIM7          0x0080  /* Enable Interrupt For Mailbox 7 */
+#define MBIM8          0x0100  /* Enable Interrupt For Mailbox 8 */
+#define MBIM9          0x0200  /* Enable Interrupt For Mailbox 9 */
+#define MBIM10         0x0400  /* Enable Interrupt For Mailbox 10 */
+#define MBIM11         0x0800  /* Enable Interrupt For Mailbox 11 */
+#define MBIM12         0x1000  /* Enable Interrupt For Mailbox 12 */
+#define MBIM13         0x2000  /* Enable Interrupt For Mailbox 13 */
+#define MBIM14         0x4000  /* Enable Interrupt For Mailbox 14 */
+#define MBIM15         0x8000  /* Enable Interrupt For Mailbox 15 */
+
+/* CAN_MBIM2 Masks */
+#define MBIM16         0x0001  /* Enable Interrupt For Mailbox 16 */
+#define MBIM17         0x0002  /* Enable Interrupt For Mailbox 17 */
+#define MBIM18         0x0004  /* Enable Interrupt For Mailbox 18 */
+#define MBIM19         0x0008  /* Enable Interrupt For Mailbox 19 */
+#define MBIM20         0x0010  /* Enable Interrupt For Mailbox 20 */
+#define MBIM21         0x0020  /* Enable Interrupt For Mailbox 21 */
+#define MBIM22         0x0040  /* Enable Interrupt For Mailbox 22 */
+#define MBIM23         0x0080  /* Enable Interrupt For Mailbox 23 */
+#define MBIM24         0x0100  /* Enable Interrupt For Mailbox 24 */
+#define MBIM25         0x0200  /* Enable Interrupt For Mailbox 25 */
+#define MBIM26         0x0400  /* Enable Interrupt For Mailbox 26 */
+#define MBIM27         0x0800  /* Enable Interrupt For Mailbox 27 */
+#define MBIM28         0x1000  /* Enable Interrupt For Mailbox 28 */
+#define MBIM29         0x2000  /* Enable Interrupt For Mailbox 29 */
+#define MBIM30         0x4000  /* Enable Interrupt For Mailbox 30 */
+#define MBIM31         0x8000  /* Enable Interrupt For Mailbox 31 */
+
+/* CAN_GIM Masks */
+#define EWTIM          0x0001  /* Enable TX Error Count Interrupt */
+#define EWRIM          0x0002  /* Enable RX Error Count Interrupt */
+#define EPIM           0x0004  /* Enable Error-Passive Mode Interrupt */
+#define BOIM           0x0008  /* Enable Bus Off Interrupt */
+#define WUIM           0x0010  /* Enable Wake-Up Interrupt */
+#define UIAIM          0x0020  /* Enable Access To Unimplemented Address Interrupt */
+#define AAIM           0x0040  /* Enable Abort Acknowledge Interrupt */
+#define RMLIM          0x0080  /* Enable RX Message Lost Interrupt */
+#define UCEIM          0x0100  /* Enable Universal Counter Overflow Interrupt */
+#define EXTIM          0x0200  /* Enable External Trigger Output Interrupt */
+#define ADIM           0x0400  /* Enable Access Denied Interrupt */
+
+/* CAN_GIS Masks */
+#define EWTIS          0x0001  /* TX Error Count IRQ Status */
+#define EWRIS          0x0002  /* RX Error Count IRQ Status */
+#define EPIS           0x0004  /* Error-Passive Mode IRQ Status */
+#define BOIS           0x0008  /* Bus Off IRQ Status */
+#define WUIS           0x0010  /* Wake-Up IRQ Status */
+#define UIAIS          0x0020  /* Access To Unimplemented Address IRQ Status */
+#define AAIS           0x0040  /* Abort Acknowledge IRQ Status */
+#define RMLIS          0x0080  /* RX Message Lost IRQ Status */
+#define UCEIS          0x0100  /* Universal Counter Overflow IRQ Status */
+#define EXTIS          0x0200  /* External Trigger Output IRQ Status */
+#define ADIS           0x0400  /* Access Denied IRQ Status */
+
+/* CAN_GIF Masks */
+#define EWTIF          0x0001  /* TX Error Count IRQ Flag */
+#define EWRIF          0x0002  /* RX Error Count IRQ Flag */
+#define EPIF           0x0004  /* Error-Passive Mode IRQ Flag */
+#define BOIF           0x0008  /* Bus Off IRQ Flag */
+#define WUIF           0x0010  /* Wake-Up IRQ Flag */
+#define UIAIF          0x0020  /* Access To Unimplemented Address IRQ Flag */
+#define AAIF           0x0040  /* Abort Acknowledge IRQ Flag */
+#define RMLIF          0x0080  /* RX Message Lost IRQ Flag */
+#define UCEIF          0x0100  /* Universal Counter Overflow IRQ Flag */
+#define EXTIF          0x0200  /* External Trigger Output IRQ Flag */
+#define ADIF           0x0400  /* Access Denied IRQ Flag */
+
+/* CAN_UCCNF Masks */
+#define UCCNF          0x000F  /* Universal Counter Mode */
+#define UC_STAMP       0x0001  /*  Timestamp Mode */
+#define UC_WDOG                0x0002  /*  Watchdog Mode */
+#define UC_AUTOTX      0x0003  /*  Auto-Transmit Mode */
+#define UC_ERROR       0x0006  /*  CAN Error Frame Count */
+#define UC_OVER                0x0007  /*  CAN Overload Frame Count */
+#define UC_LOST                0x0008  /*  Arbitration Lost During TX Count */
+#define UC_AA          0x0009  /*  TX Abort Count */
+#define UC_TA          0x000A  /*  TX Successful Count */
+#define UC_REJECT      0x000B  /*  RX Message Rejected Count */
+#define UC_RML         0x000C  /*  RX Message Lost Count */
+#define UC_RX          0x000D  /*  Total Successful RX Messages Count */
+#define UC_RMP         0x000E  /*  Successful RX W/Matching ID Count */
+#define UC_ALL         0x000F  /*  Correct Message On CAN Bus Line Count */
+#define UCRC           0x0020  /* Universal Counter Reload/Clear */
+#define UCCT           0x0040  /* Universal Counter CAN Trigger */
+#define UCE                    0x0080  /* Universal Counter Enable */
+
+/* CAN_ESR Masks */
+#define ACKE           0x0004  /* Acknowledge Error */
+#define SER                    0x0008  /* Stuff Error */
+#define CRCE           0x0010  /* CRC Error */
+#define SA0                    0x0020  /* Stuck At Dominant Error */
+#define BEF                    0x0040  /* Bit Error Flag */
+#define FER                    0x0080  /* Form Error Flag */
+
+/* CAN_EWR Masks */
+#define EWLREC         0x00FF  /* RX Error Count Limit (For EWRIS) */
+#define EWLTEC         0xFF00  /* TX Error Count Limit (For EWTIS) */
+
+#endif
index b558908..9626cf7 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * bfin_sport.h - userspace header for bfin sport driver
+ * bfin_sport.h - interface to Blackfin SPORTs
  *
- * Copyright 2004-2008 Analog Devices Inc.
+ * Copyright 2004-2009 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -9,16 +9,6 @@
 #ifndef __BFIN_SPORT_H__
 #define __BFIN_SPORT_H__
 
-#ifdef __KERNEL__
-#include <linux/cdev.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#endif
-
-#define SPORT_MAJOR    237
-#define SPORT_NR_DEVS  2
-
 /* Sport mode: it can be set to TDM, i2s or others */
 #define NORM_MODE      0x0
 #define TDM_MODE       0x1
@@ -35,7 +25,7 @@ struct sport_config {
        unsigned int mode:3;
 
        /* if TDM mode is selected, channels must be set */
-       int channels;           /* Must be in 8 units */
+       int channels;   /* Must be in 8 units */
        unsigned int frame_delay:4;     /* Delay between frame sync pulse and first bit */
 
        /* I2S mode */
@@ -69,94 +59,137 @@ struct sport_config {
 
 #ifdef __KERNEL__
 
-struct sport_register {
-       unsigned short tcr1;
-       unsigned short reserved0;
-       unsigned short tcr2;
-       unsigned short reserved1;
-       unsigned short tclkdiv;
-       unsigned short reserved2;
-       unsigned short tfsdiv;
-       unsigned short reserved3;
-       unsigned long tx;
-       unsigned long reserved_l0;
-       unsigned long rx;
-       unsigned long reserved_l1;
-       unsigned short rcr1;
-       unsigned short reserved4;
-       unsigned short rcr2;
-       unsigned short reserved5;
-       unsigned short rclkdiv;
-       unsigned short reserved6;
-       unsigned short rfsdiv;
-       unsigned short reserved7;
-       unsigned short stat;
-       unsigned short reserved8;
-       unsigned short chnl;
-       unsigned short reserved9;
-       unsigned short mcmc1;
-       unsigned short reserved10;
-       unsigned short mcmc2;
-       unsigned short reserved11;
-       unsigned long mtcs0;
-       unsigned long mtcs1;
-       unsigned long mtcs2;
-       unsigned long mtcs3;
-       unsigned long mrcs0;
-       unsigned long mrcs1;
-       unsigned long mrcs2;
-       unsigned long mrcs3;
-};
-
-struct sport_dev {
-       struct cdev cdev;       /* Char device structure */
-
-       int sport_num;
+#include <linux/types.h>
 
-       int dma_rx_chan;
-       int dma_tx_chan;
-
-       int rx_irq;
-       unsigned char *rx_buf;  /* Buffer store the received data */
-       int rx_len;             /* How many bytes will be received */
-       int rx_received;        /* How many bytes has been received */
-
-       int tx_irq;
-       const unsigned char *tx_buf;
-       int tx_len;
-       int tx_sent;
-
-       int err_irq;
-
-       struct mutex mutex;     /* mutual exclusion semaphore */
-       struct task_struct *task;
-
-       wait_queue_head_t waitq;
-       int     wait_con;
-       struct sport_register *regs;
-       struct sport_config config;
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+struct sport_register {
+       __BFP(tcr1);
+       __BFP(tcr2);
+       __BFP(tclkdiv);
+       __BFP(tfsdiv);
+       union {
+               u32 tx32;
+               u16 tx16;
+       };
+       u32 __pad_tx;
+       union {
+               u32 rx32;       /* use the anomaly wrapper below */
+               u16 rx16;
+       };
+       u32 __pad_rx;
+       __BFP(rcr1);
+       __BFP(rcr2);
+       __BFP(rclkdiv);
+       __BFP(rfsdiv);
+       __BFP(stat);
+       __BFP(chnl);
+       __BFP(mcmc1);
+       __BFP(mcmc2);
+       u32 mtcs0;
+       u32 mtcs1;
+       u32 mtcs2;
+       u32 mtcs3;
+       u32 mrcs0;
+       u32 mrcs1;
+       u32 mrcs2;
+       u32 mrcs3;
 };
+#undef __BFP
+
+#define bfin_read_sport_rx32(base) \
+({ \
+       struct sport_register *__mmrs = (void *)base; \
+       u32 __ret; \
+       unsigned long flags; \
+       if (ANOMALY_05000473) \
+               local_irq_save(flags); \
+       __ret = __mmrs->rx32; \
+       if (ANOMALY_05000473) \
+               local_irq_restore(flags); \
+       __ret; \
+})
 
 #endif
 
-#define SPORT_TCR1     0
-#define        SPORT_TCR2      1
-#define        SPORT_TCLKDIV   2
-#define        SPORT_TFSDIV    3
-#define        SPORT_RCR1      8
-#define        SPORT_RCR2      9
-#define SPORT_RCLKDIV  10
-#define        SPORT_RFSDIV    11
-#define SPORT_CHANNEL  13
-#define SPORT_MCMC1    14
-#define SPORT_MCMC2    15
-#define SPORT_MTCS0    16
-#define SPORT_MTCS1    17
-#define SPORT_MTCS2    18
-#define SPORT_MTCS3    19
-#define SPORT_MRCS0    20
-#define SPORT_MRCS1    21
-#define SPORT_MRCS2    22
-#define SPORT_MRCS3    23
+/* Workaround defBF*.h SPORT MMRs till they get cleansed */
+#undef DTYPE_NORM
+#undef SLEN
+#undef SP_WOFF
+#undef SP_WSIZE
+
+/* SPORT_TCR1 Masks */
+#define TSPEN          0x0001  /* TX enable */
+#define ITCLK          0x0002  /* Internal TX Clock Select */
+#define TDTYPE         0x000C  /* TX Data Formatting Select */
+#define DTYPE_NORM     0x0000  /* Data Format Normal */
+#define DTYPE_ULAW     0x0008  /* Compand Using u-Law */
+#define DTYPE_ALAW     0x000C  /* Compand Using A-Law */
+#define TLSBIT         0x0010  /* TX Bit Order */
+#define ITFS           0x0200  /* Internal TX Frame Sync Select */
+#define TFSR           0x0400  /* TX Frame Sync Required Select */
+#define DITFS          0x0800  /* Data Independent TX Frame Sync Select */
+#define LTFS           0x1000  /* Low TX Frame Sync Select */
+#define LATFS          0x2000  /* Late TX Frame Sync Select */
+#define TCKFE          0x4000  /* TX Clock Falling Edge Select */
+
+/* SPORT_TCR2 Masks */
+#define SLEN           0x001F  /* SPORT TX Word Length (2 - 31) */
+#define DP_SLEN(x)     BFIN_DEPOSIT(SLEN, x)
+#define EX_SLEN(x)     BFIN_EXTRACT(SLEN, x)
+#define TXSE           0x0100  /* TX Secondary Enable */
+#define TSFSE          0x0200  /* TX Stereo Frame Sync Enable */
+#define TRFST          0x0400  /* TX Right-First Data Order */
+
+/* SPORT_RCR1 Masks */
+#define RSPEN          0x0001  /* RX enable */
+#define IRCLK          0x0002  /* Internal RX Clock Select */
+#define RDTYPE         0x000C  /* RX Data Formatting Select */
+/* DTYPE_* defined above */
+#define RLSBIT         0x0010  /* RX Bit Order */
+#define IRFS           0x0200  /* Internal RX Frame Sync Select */
+#define RFSR           0x0400  /* RX Frame Sync Required Select */
+#define LRFS           0x1000  /* Low RX Frame Sync Select */
+#define LARFS          0x2000  /* Late RX Frame Sync Select */
+#define RCKFE          0x4000  /* RX Clock Falling Edge Select */
+
+/* SPORT_RCR2 Masks */
+/* SLEN defined above */
+#define RXSE           0x0100  /* RX Secondary Enable */
+#define RSFSE          0x0200  /* RX Stereo Frame Sync Enable */
+#define RRFST          0x0400  /* Right-First Data Order */
+
+/* SPORT_STAT Masks */
+#define RXNE           0x0001  /* RX FIFO Not Empty Status */
+#define RUVF           0x0002  /* RX Underflow Status */
+#define ROVF           0x0004  /* RX Overflow Status */
+#define TXF            0x0008  /* TX FIFO Full Status */
+#define TUVF           0x0010  /* TX Underflow Status */
+#define TOVF           0x0020  /* TX Overflow Status */
+#define TXHRE          0x0040  /* TX Hold Register Empty */
+
+/* SPORT_MCMC1 Masks */
+#define SP_WOFF                0x03FF  /* Multichannel Window Offset Field */
+#define DP_SP_WOFF(x)  BFIN_DEPOSIT(SP_WOFF, x)
+#define EX_SP_WOFF(x)  BFIN_EXTRACT(SP_WOFF, x)
+#define SP_WSIZE       0xF000  /* Multichannel Window Size Field */
+#define DP_SP_WSIZE(x) BFIN_DEPOSIT(SP_WSIZE, x)
+#define EX_SP_WSIZE(x) BFIN_EXTRACT(SP_WSIZE, x)
+
+/* SPORT_MCMC2 Masks */
+#define MCCRM          0x0003  /* Multichannel Clock Recovery Mode */
+#define REC_BYPASS     0x0000  /* Bypass Mode (No Clock Recovery) */
+#define REC_2FROM4     0x0002  /* Recover 2 MHz Clock from 4 MHz Clock */
+#define REC_8FROM16    0x0003  /* Recover 8 MHz Clock from 16 MHz Clock */
+#define MCDTXPE                0x0004  /* Multichannel DMA Transmit Packing */
+#define MCDRXPE                0x0008  /* Multichannel DMA Receive Packing */
+#define MCMEN          0x0010  /* Multichannel Frame Mode Enable */
+#define FSDR           0x0080  /* Multichannel Frame Sync to Data Relationship */
+#define MFD            0xF000  /* Multichannel Frame Delay */
+#define DP_MFD(x)      BFIN_DEPOSIT(MFD, x)
+#define EX_MFD(x)      BFIN_EXTRACT(MFD, x)
 
 #endif
diff --git a/arch/blackfin/include/asm/bfin_watchdog.h b/arch/blackfin/include/asm/bfin_watchdog.h
new file mode 100644 (file)
index 0000000..dce0982
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * bfin_watchdog.h - Blackfin watchdog definitions
+ *
+ * Copyright 2006-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _BFIN_WATCHDOG_H
+#define _BFIN_WATCHDOG_H
+
+/* Bit in SWRST that indicates boot caused by watchdog */
+#define SWRST_RESET_WDOG 0x4000
+
+/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
+#define WDOG_EXPIRED 0x8000
+
+/* Masks for WDEV field in WDOG_CTL register */
+#define ICTL_RESET   0x0
+#define ICTL_NMI     0x2
+#define ICTL_GPI     0x4
+#define ICTL_NONE    0x6
+#define ICTL_MASK    0x6
+
+/* Masks for WDEN field in WDOG_CTL register */
+#define WDEN_MASK    0x0FF0
+#define WDEN_ENABLE  0x0000
+#define WDEN_DISABLE 0x0AD0
+
+#endif
index a2ff3fb..605ba8e 100644 (file)
@@ -7,22 +7,41 @@
 #ifndef _BLACKFIN_BITOPS_H
 #define _BLACKFIN_BITOPS_H
 
-#ifndef CONFIG_SMP
-# include <asm-generic/bitops.h>
-#else
+#include <linux/compiler.h>
+
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
 
 #ifndef _LINUX_BITOPS_H
 #error only <linux/bitops.h> can be included directly
 #endif
 
-#include <linux/compiler.h>
-#include <asm/byteorder.h>     /* swab32 */
-
-#include <asm-generic/bitops/ffs.h>
-#include <asm-generic/bitops/__ffs.h>
 #include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/lock.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
+
+#ifndef CONFIG_SMP
+#include <linux/irqflags.h>
+
+/*
+ * clear_bit may not imply a memory barrier
+ */
+#ifndef smp_mb__before_clear_bit
+#define smp_mb__before_clear_bit()     smp_mb()
+#define smp_mb__after_clear_bit()      smp_mb()
+#endif
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
+#else
 
+#include <asm/byteorder.h>     /* swab32 */
 #include <linux/linkage.h>
 
 asmlinkage int __raw_bit_set_asm(volatile unsigned long *addr, int nr);
@@ -89,19 +108,36 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
 
 #include <asm-generic/bitops/non-atomic.h>
 
-#include <asm-generic/bitops/find.h>
-#include <asm-generic/bitops/hweight.h>
-#include <asm-generic/bitops/lock.h>
+#endif /* CONFIG_SMP */
 
-#include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
 
-#include <asm-generic/bitops/minix.h>
+static inline unsigned int hweight32(unsigned int w)
+{
+       unsigned int res;
 
-#include <asm-generic/bitops/fls.h>
-#include <asm-generic/bitops/__fls.h>
-#include <asm-generic/bitops/fls64.h>
+       __asm__ ("%0.l = ONES %0;"
+               "%0 = %0.l (Z);"
+               : "=d" (res) : "d" (w));
+       return res;
+}
 
-#endif /* CONFIG_SMP */
+static inline unsigned int hweight64(__u64 w)
+{
+       return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+}
+
+static inline unsigned int hweight16(unsigned int w)
+{
+       return hweight32(w & 0xffff);
+}
+
+static inline unsigned int hweight8(unsigned int w)
+{
+       return hweight32(w & 0xff);
+}
 
 #endif                         /* _BLACKFIN_BITOPS_H */
index 5dffaf5..1f90603 100644 (file)
 #else
        cli r0;
 #endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+       sp += -12;
+       call _trace_hardirqs_off;
+       sp += 12;
+#endif
        [--sp] = RETI;  /*orig_pc*/
        /* Clear all L registers.  */
        r0 = 0 (x);
        RETN = [sp++];
        RETX = [sp++];
        RETI = [sp++];
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+       sp += -12;
+       call _trace_hardirqs_on;
+       sp += 12;
+#endif
+
        RETS = [sp++];
 
 #ifdef CONFIG_SMP
 
        (R7:0, P5:0) = [SP++];
 .endm
+
+.macro pseudo_long_call func:req, scratch:req
+#ifdef CONFIG_ROMKERNEL
+       \scratch\().l = \func;
+       \scratch\().h = \func;
+       call (\scratch);
+#else
+       call \func;
+#endif
+.endm
index b191dc6..16883e5 100644 (file)
@@ -17,8 +17,6 @@ struct blackfin_cpudata {
        struct task_struct *idle;
        unsigned int imemctl;
        unsigned int dmemctl;
-       unsigned long dcache_invld_count;
-       unsigned long icache_invld_count;
 };
 
 DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data);
index 2590646..f342ff0 100644 (file)
@@ -12,6 +12,8 @@
 #include <mach/anomaly.h>
 
 #define MK_BMSK_(x) (1<<x)
+#define BFIN_DEPOSIT(mask, x)  (((x) << __ffs(mask)) & (mask))
+#define BFIN_EXTRACT(mask, x)  (((x) & (mask)) >> __ffs(mask))
 
 #ifndef __ASSEMBLY__
 
 # define NOP_PAD_ANOMALY_05000198
 #endif
 
-#define bfin_read8(addr) ({ \
-       uint32_t __v; \
+#define _bfin_readX(addr, size, asm_size, asm_ext) ({ \
+       u32 __v; \
        __asm__ __volatile__( \
                NOP_PAD_ANOMALY_05000198 \
-               "%0 = b[%1] (z);" \
+               "%0 = " #asm_size "[%1]" #asm_ext ";" \
                : "=d" (__v) \
                : "a" (addr) \
        ); \
        __v; })
-
-#define bfin_read16(addr) ({ \
-       uint32_t __v; \
-       __asm__ __volatile__( \
-               NOP_PAD_ANOMALY_05000198 \
-               "%0 = w[%1] (z);" \
-               : "=d" (__v) \
-               : "a" (addr) \
-       ); \
-       __v; })
-
-#define bfin_read32(addr) ({ \
-       uint32_t __v; \
-       __asm__ __volatile__( \
-               NOP_PAD_ANOMALY_05000198 \
-               "%0 = [%1];" \
-               : "=d" (__v) \
-               : "a" (addr) \
-       ); \
-       __v; })
-
-#define bfin_write8(addr, val) \
+#define _bfin_writeX(addr, val, size, asm_size) \
        __asm__ __volatile__( \
                NOP_PAD_ANOMALY_05000198 \
-               "b[%0] = %1;" \
+               #asm_size "[%0] = %1;" \
                : \
-               : "a" (addr), "d" ((uint8_t)(val)) \
+               : "a" (addr), "d" ((u##size)(val)) \
                : "memory" \
        )
 
-#define bfin_write16(addr, val) \
-       __asm__ __volatile__( \
-               NOP_PAD_ANOMALY_05000198 \
-               "w[%0] = %1;" \
-               : \
-               : "a" (addr), "d" ((uint16_t)(val)) \
-               : "memory" \
-       )
-
-#define bfin_write32(addr, val) \
-       __asm__ __volatile__( \
-               NOP_PAD_ANOMALY_05000198 \
-               "[%0] = %1;" \
-               : \
-               : "a" (addr), "d" (val) \
-               : "memory" \
-       )
+#define bfin_read8(addr)  _bfin_readX(addr,  8, b, (z))
+#define bfin_read16(addr) _bfin_readX(addr, 16, w, (z))
+#define bfin_read32(addr) _bfin_readX(addr, 32,  ,    )
+#define bfin_write8(addr, val)  _bfin_writeX(addr, val,  8, b)
+#define bfin_write16(addr, val) _bfin_writeX(addr, val, 16, w)
+#define bfin_write32(addr, val) _bfin_writeX(addr, val, 32,  )
 
 #endif /* __ASSEMBLY__ */
 
index c31f91c..171d8de 100644 (file)
@@ -30,10 +30,22 @@ __asm__ __volatile__ (
 
 #define        HZSCALE         (268435456 / (1000000/HZ))
 
-static inline void udelay(unsigned long usecs)
+static inline unsigned long __to_delay(unsigned long scale)
 {
        extern unsigned long loops_per_jiffy;
-       __delay((((usecs * HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6);
+       return (((scale * HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6;
+}
+
+static inline void udelay(unsigned long usecs)
+{
+       __delay(__to_delay(usecs));
 }
 
+static inline void ndelay(unsigned long nsecs)
+{
+       __delay(__to_delay(1) * nsecs / 1000);
+}
+
+#define ndelay ndelay
+
 #endif
index 413a303..212cb80 100644 (file)
@@ -44,13 +44,8 @@ dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 extern void
 __dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir);
 static inline void
-_dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir)
+__dma_sync_inline(dma_addr_t addr, size_t size, enum dma_data_direction dir)
 {
-       if (!__builtin_constant_p(dir)) {
-               __dma_sync(addr, size, dir);
-               return;
-       }
-
        switch (dir) {
        case DMA_NONE:
                BUG();
@@ -64,6 +59,14 @@ _dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir)
                break;
        }
 }
+static inline void
+_dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+       if (__builtin_constant_p(dir))
+               __dma_sync_inline(addr, size, dir);
+       else
+               __dma_sync(addr, size, dir);
+}
 
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
index bd2e622..2c09b1d 100644 (file)
@@ -262,6 +262,10 @@ static inline void dma_disable_irq(unsigned int channel)
 {
        disable_irq(dma_ch[channel].irq);
 }
+static inline void dma_disable_irq_nosync(unsigned int channel)
+{
+       disable_irq_nosync(dma_ch[channel].irq);
+}
 static inline void dma_enable_irq(unsigned int channel)
 {
        enable_irq(dma_ch[channel].irq);
index 1597ae5..efcc3ae 100644 (file)
@@ -75,7 +75,7 @@
 
 #define VLEV                   0x00F0  /* Internal Voltage Level */
 #ifdef __ADSPBF52x__
-#define VLEV_085               0x0040  /* VLEV = 0.85 V (-5% - +10% Accuracy) */
+#define VLEV_085               0x0040  /* VLEV = 0.85 V (-5% - +10% Accuracy) */
 #define VLEV_090               0x0050  /* VLEV = 0.90 V (-5% - +10% Accuracy) */
 #define VLEV_095               0x0060  /* VLEV = 0.95 V (-5% - +10% Accuracy) */
 #define VLEV_100               0x0070  /* VLEV = 1.00 V (-5% - +10% Accuracy) */
@@ -84,7 +84,7 @@
 #define VLEV_115               0x00A0  /* VLEV = 1.15 V (-5% - +10% Accuracy) */
 #define VLEV_120               0x00B0  /* VLEV = 1.20 V (-5% - +10% Accuracy) */
 #else
-#define VLEV_085               0x0060  /* VLEV = 0.85 V (-5% - +10% Accuracy) */
+#define VLEV_085               0x0060  /* VLEV = 0.85 V (-5% - +10% Accuracy) */
 #define VLEV_090               0x0070  /* VLEV = 0.90 V (-5% - +10% Accuracy) */
 #define VLEV_095               0x0080  /* VLEV = 0.95 V (-5% - +10% Accuracy) */
 #define VLEV_100               0x0090  /* VLEV = 1.00 V (-5% - +10% Accuracy) */
index 5b50f0e..117713a 100644 (file)
 #define EF_BFIN_CODE_IN_L2     0x00000040      /* --code-in-l2 */
 #define EF_BFIN_DATA_IN_L2     0x00000080      /* --data-in-l2 */
 
+#if 1  /* core dumps not supported, but linux/elfcore.h needs these */
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG 40 /* (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) */
+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef struct { } elf_fpregset_t;
+#endif
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -55,6 +58,9 @@ do {                                                                                  \
        _regs->p2       = _dynamic_addr;                                \
 } while(0)
 
+#if 0
+#define CORE_DUMP_USE_REGSET
+#endif
 #define ELF_FDPIC_CORE_EFLAGS  EF_BFIN_FDPIC
 #define ELF_EXEC_PAGESIZE      4096
 
index 90c9b40..4cfe2d9 100644 (file)
 
 #define MCOUNT_INSN_SIZE       6 /* sizeof "[++sp] = rets; call __mcount;" */
 
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_FRAME_POINTER
+#include <linux/mm.h>
+
+extern inline void *return_address(unsigned int level)
+{
+       unsigned long *endstack, *fp, *ret_addr;
+       unsigned int current_level = 0;
+
+       if (level == 0)
+               return __builtin_return_address(0);
+
+       fp = (unsigned long *)__builtin_frame_address(0);
+       endstack = (unsigned long *)PAGE_ALIGN((unsigned long)&level);
+
+       while (((unsigned long)fp & 0x3) == 0 && fp &&
+              (fp + 1) < endstack && current_level < level) {
+               fp = (unsigned long *)*fp;
+               current_level++;
+       }
+
+       if (((unsigned long)fp & 0x3) == 0 && fp &&
+           (fp + 1) < endstack)
+               ret_addr = (unsigned long *)*(fp + 1);
+       else
+               ret_addr = NULL;
+
+       return ret_addr;
+}
+
+#else
+
+extern inline void *return_address(unsigned int level)
+{
+       return NULL;
+}
+
+#endif /* CONFIG_FRAME_POINTER */
+
+#define HAVE_ARCH_CALLER_ADDR
+
+/* inline function or macro may lead to unexpected result */
+#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
+#define CALLER_ADDR1 ((unsigned long)return_address(1))
+#define CALLER_ADDR2 ((unsigned long)return_address(2))
+#define CALLER_ADDR3 ((unsigned long)return_address(3))
+#define CALLER_ADDR4 ((unsigned long)return_address(4))
+#define CALLER_ADDR5 ((unsigned long)return_address(5))
+#define CALLER_ADDR6 ((unsigned long)return_address(6))
+
+#endif /* __ASSEMBLY__ */
+
 #endif
index 539468a..91bd2d7 100644 (file)
@@ -70,6 +70,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/compiler.h>
+
 /***********************************************************
 *
 * FUNCTIONS: Blackfin General Purpose Ports Access Functions
@@ -223,6 +225,9 @@ int bfin_gpio_direction_output(unsigned gpio, int value);
 int bfin_gpio_get_value(unsigned gpio);
 void bfin_gpio_set_value(unsigned gpio, int value);
 
+#include <asm/irq.h>
+#include <asm/errno.h>
+
 #ifdef CONFIG_GPIOLIB
 #include <asm-generic/gpio.h>          /* cansleep wrappers */
 
@@ -247,6 +252,11 @@ static inline int gpio_cansleep(unsigned int gpio)
        return __gpio_cansleep(gpio);
 }
 
+static inline int gpio_to_irq(unsigned gpio)
+{
+       return __gpio_to_irq(gpio);
+}
+
 #else /* !CONFIG_GPIOLIB */
 
 static inline int gpio_request(unsigned gpio, const char *label)
@@ -279,10 +289,6 @@ static inline void gpio_set_value(unsigned gpio, int value)
        return bfin_gpio_set_value(gpio, value);
 }
 
-#include <asm-generic/gpio.h>          /* cansleep wrappers */
-#endif /* !CONFIG_GPIOLIB */
-#include <asm/irq.h>
-
 static inline int gpio_to_irq(unsigned gpio)
 {
        if (likely(gpio < MAX_BLACKFIN_GPIOS))
@@ -291,6 +297,9 @@ static inline int gpio_to_irq(unsigned gpio)
        return -EINVAL;
 }
 
+#include <asm-generic/gpio.h>          /* cansleep wrappers */
+#endif /* !CONFIG_GPIOLIB */
+
 static inline int irq_to_gpio(unsigned irq)
 {
        return (irq - GPIO_IRQ_BASE);
index e7c0623..12f4060 100644 (file)
@@ -12,6 +12,9 @@
 
 #include <linux/irqflags.h>
 
+/* IRQs that may be used by external irq_chip controllers */
+#define NR_SPARE_IRQS  32
+
 #include <mach/anomaly.h>
 
 /* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
@@ -35,4 +38,8 @@
 
 #include <asm-generic/irq.h>
 
+#ifdef CONFIG_NMI_WATCHDOG
+# define ARCH_HAS_NMI_WATCHDOG
+#endif
+
 #endif                         /* _BFIN_IRQ_H_ */
index ae8ef4f..7f363d7 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/cplbinit.h>
+#include <asm/sections.h>
 
 /* Note: L1 stacks are CPU-private things, so we bluntly disable this
    feature in SMP mode, and use the per-CPU scratch SRAM bank only to
@@ -117,9 +118,16 @@ static inline void protect_page(struct mm_struct *mm, unsigned long addr,
                                unsigned long flags)
 {
        unsigned long *mask = mm->context.page_rwx_mask;
-       unsigned long page = addr >> 12;
-       unsigned long idx = page >> 5;
-       unsigned long bit = 1 << (page & 31);
+       unsigned long page;
+       unsigned long idx;
+       unsigned long bit;
+
+       if (unlikely(addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE))
+               page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> 12;
+       else
+               page = addr >> 12;
+       idx = page >> 5;
+       bit = 1 << (page & 31);
 
        if (flags & VM_READ)
                mask[idx] |= bit;
diff --git a/arch/blackfin/include/asm/nmi.h b/arch/blackfin/include/asm/nmi.h
new file mode 100644 (file)
index 0000000..b9caac4
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2
+ */
+
+#ifndef _BFIN_NMI_H_
+#define _BFIN_NMI_H_
+
+#include <linux/nmi.h>
+
+#endif
index 1d04e40..d0ce975 100644 (file)
@@ -15,4 +15,7 @@
        ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
+
 #endif
index b33a448..aaa1c6c 100644 (file)
@@ -24,6 +24,8 @@
 
 #ifndef __ASSEMBLY__
 
+struct task_struct;
+
 /* this struct defines the way the registers are stored on the
    stack during a system call. */
 
@@ -101,9 +103,30 @@ struct pt_regs {
    master interrupt enable.  */
 #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
 #define instruction_pointer(regs) ((regs)->pc)
+#define user_stack_pointer(regs)  ((regs)->usp)
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
 
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *child);
+extern void user_disable_single_step(struct task_struct *child);
+/* common code demands this function */
+#define ptrace_disable(child) user_disable_single_step(child)
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+#define task_pt_regs(task) \
+       (struct pt_regs *) \
+           ((unsigned long)task_stack_page(task) + \
+            (THREAD_SIZE - sizeof(struct pt_regs)))
+
 #endif  /*  __KERNEL__  */
 
 #endif                         /* __ASSEMBLY__ */
@@ -173,4 +196,6 @@ extern void show_regs(struct pt_regs *);
 #define PT_FDPIC_EXEC 232
 #define PT_FDPIC_INTERP 236
 
+#define PT_LAST_PSEUDO PT_FDPIC_INTERP
+
 #endif                         /* _BFIN_PTRACE_H */
index 42f6c53..14a3e66 100644 (file)
@@ -21,6 +21,9 @@ extern unsigned long memory_start, memory_end, physical_mem_end;
 extern char _stext_l1[], _etext_l1[], _text_l1_lma[], __weak _text_l1_len[];
 extern char _sdata_l1[], _edata_l1[], _sbss_l1[], _ebss_l1[],
        _data_l1_lma[], __weak _data_l1_len[];
+#ifdef CONFIG_ROMKERNEL
+extern char _data_lma[], _data_len[], _sinitdata[], _einitdata[], _init_data_lma[], _init_data_len[];
+#endif
 extern char _sdata_b_l1[], _edata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
        _data_b_l1_lma[], __weak _data_b_l1_len[];
 extern char _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[],
index 6a0fe94..f5b5379 100644 (file)
@@ -22,8 +22,23 @@ extern char coreb_trampoline_start, coreb_trampoline_end;
 struct corelock_slot {
        int lock;
 };
+extern struct corelock_slot corelock;
+
+#ifdef __ARCH_SYNC_CORE_ICACHE
+extern unsigned long icache_invld_count[NR_CPUS];
+#endif
+#ifdef __ARCH_SYNC_CORE_DCACHE
+extern unsigned long dcache_invld_count[NR_CPUS];
+#endif
 
 void smp_icache_flush_range_others(unsigned long start,
                                   unsigned long end);
+#ifdef CONFIG_HOTPLUG_CPU
+void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
+void cpu_die(void);
+void platform_cpu_die(void);
+int __cpu_disable(void);
+int __cpu_die(unsigned int cpu);
+#endif
 
 #endif /* !__ASM_BLACKFIN_SMP_H */
diff --git a/arch/blackfin/include/asm/syscall.h b/arch/blackfin/include/asm/syscall.h
new file mode 100644 (file)
index 0000000..4921a48
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Magic syscall break down functions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BLACKFIN_SYSCALL_H__
+#define __ASM_BLACKFIN_SYSCALL_H__
+
+/*
+ * Blackfin syscalls are simple:
+ *     enter:
+ *             p0: syscall number
+ *             r{0,1,2,3,4,5}: syscall args 0,1,2,3,4,5
+ *     exit:
+ *             r0: return/error value
+ */
+
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+       return regs->p0;
+}
+
+static inline void
+syscall_rollback(struct task_struct *task, struct pt_regs *regs)
+{
+       regs->p0 = regs->orig_p0;
+}
+
+static inline long
+syscall_get_error(struct task_struct *task, struct pt_regs *regs)
+{
+       return IS_ERR_VALUE(regs->r0) ? regs->r0 : 0;
+}
+
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
+{
+       return regs->r0;
+}
+
+static inline void
+syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
+                         int error, long val)
+{
+       regs->r0 = error ? -error : val;
+}
+
+/**
+ *     syscall_get_arguments()
+ *     @task:   unused
+ *     @regs:   the register layout to extract syscall arguments from
+ *     @i:      first syscall argument to extract
+ *     @n:      number of syscall arguments to extract
+ *     @args:   array to return the syscall arguments in
+ *
+ * args[0] gets i'th argument, args[n - 1] gets the i+n-1'th argument
+ */
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+                      unsigned int i, unsigned int n, unsigned long *args)
+{
+       /*
+        * Assume the ptrace layout doesn't change -- r5 is first in memory,
+        * then r4, ..., then r0.  So we simply reverse the ptrace register
+        * array in memory to store into the args array.
+        */
+       long *aregs = &regs->r0 - i;
+
+       BUG_ON(i > 5 || i + n > 6);
+
+       while (n--)
+               *args++ = *aregs--;
+}
+
+/* See syscall_get_arguments() comments */
+static inline void
+syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
+                      unsigned int i, unsigned int n, const unsigned long *args)
+{
+       long *aregs = &regs->r0 - i;
+
+       BUG_ON(i > 5 || i + n > 6);
+
+       while (n--)
+               *aregs-- = *args++;
+}
+
+#endif
index a40d936..e9a5614 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2009 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -17,7 +17,7 @@
 /* Thread Align Mask to reach to the top of the stack
  * for any process
  */
-#define ALIGN_PAGE_MASK         0xffffe000
+#define ALIGN_PAGE_MASK                0xffffe000
 
 /*
  * Size of kernel stack for each process. This must be a power of 2...
@@ -57,7 +57,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
-       .preempt_count  = INIT_PREEMPT_COUNT,   \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
@@ -73,8 +73,7 @@ __attribute_const__
 static inline struct thread_info *current_thread_info(void)
 {
        struct thread_info *ti;
-      __asm__("%0 = sp;" : "=da"(ti) :
-       );
+       __asm__("%0 = sp;" : "=da"(ti));
        return (struct thread_info *)((long)ti & ~((long)THREAD_SIZE-1));
 }
 
@@ -99,21 +98,23 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NEED_RESCHED       2       /* rescheduling necessary */
 #define TIF_POLLING_NRFLAG     3       /* true if poll_idle() is polling
                                           TIF_NEED_RESCHED */
-#define TIF_MEMDIE              4
+#define TIF_MEMDIE             4
 #define TIF_RESTORE_SIGMASK    5       /* restore signal mask in do_signal() */
-#define TIF_FREEZE              6       /* is freezing for suspend */
-#define TIF_IRQ_SYNC            7       /* sync pipeline stage */
-#define TIF_NOTIFY_RESUME       8       /* callback before returning to user */
+#define TIF_FREEZE             6       /* is freezing for suspend */
+#define TIF_IRQ_SYNC           7       /* sync pipeline stage */
+#define TIF_NOTIFY_RESUME      8       /* callback before returning to user */
+#define TIF_SINGLESTEP         9
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
-#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
-#define _TIF_FREEZE             (1<<TIF_FREEZE)
-#define _TIF_IRQ_SYNC           (1<<TIF_IRQ_SYNC)
+#define _TIF_FREEZE            (1<<TIF_FREEZE)
+#define _TIF_IRQ_SYNC          (1<<TIF_IRQ_SYNC)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 
 #define _TIF_WORK_MASK         0x0000FFFE      /* work to do on interrupt/exception return */
 
index 589e937..9ca7db8 100644 (file)
@@ -23,9 +23,7 @@
  */
 
 #ifndef CONFIG_CPU_FREQ
-#define TIME_SCALE 1
-#define __bfin_cycles_off (0)
-#define __bfin_cycles_mod (0)
+# define TIME_SCALE 1
 #else
 /*
  * Blackfin CPU frequency scaling supports max Core Clock 1, 1/2 and 1/4 .
  * adjust the Core Timer Presale Register. This way we don't lose time.
  */
 #define TIME_SCALE 4
+
+# ifdef CONFIG_CYCLES_CLOCKSOURCE
 extern unsigned long long __bfin_cycles_off;
 extern unsigned int __bfin_cycles_mod;
+# endif
+#endif
+
+#if defined(CONFIG_TICKSOURCE_CORETMR)
+extern void bfin_coretmr_init(void);
+extern void bfin_coretmr_clockevent_init(void);
 #endif
 
-extern void __init setup_core_timer(void);
 #endif
index a8ddbc8..346a421 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_CPLB_INFO)              += cplbinfo.o
 obj-$(CONFIG_MODULES)                += module.o
 obj-$(CONFIG_KGDB)                   += kgdb.o
 obj-$(CONFIG_KGDB_TESTS)             += kgdb_test.o
+obj-$(CONFIG_NMI_WATCHDOG)           += nmi.o
 obj-$(CONFIG_EARLY_PRINTK)           += early_printk.o
 obj-$(CONFIG_EARLY_PRINTK)           += shadow_console.o
 obj-$(CONFIG_STACKTRACE)             += stacktrace.o
index 924c002..26403d1 100644 (file)
@@ -91,7 +91,7 @@ late_initcall(proc_dma_init);
  */
 int request_dma(unsigned int channel, const char *device_id)
 {
-       pr_debug("request_dma() : BEGIN \n");
+       pr_debug("request_dma() : BEGIN\n");
 
        if (device_id == NULL)
                printk(KERN_WARNING "request_dma(%u): no device_id given\n", channel);
@@ -107,7 +107,7 @@ int request_dma(unsigned int channel, const char *device_id)
 #endif
 
        if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
-               pr_debug("DMA CHANNEL IN USE  \n");
+               pr_debug("DMA CHANNEL IN USE\n");
                return -EBUSY;
        }
 
@@ -131,7 +131,7 @@ int request_dma(unsigned int channel, const char *device_id)
         * you have to request DMA, before doing any operations on
         * descriptor/channel
         */
-       pr_debug("request_dma() : END  \n");
+       pr_debug("request_dma() : END\n");
        return 0;
 }
 EXPORT_SYMBOL(request_dma);
@@ -171,7 +171,7 @@ static void clear_dma_buffer(unsigned int channel)
 
 void free_dma(unsigned int channel)
 {
-       pr_debug("freedma() : BEGIN \n");
+       pr_debug("freedma() : BEGIN\n");
        BUG_ON(channel >= MAX_DMA_CHANNELS ||
                        !atomic_read(&dma_ch[channel].chan_status));
 
@@ -185,7 +185,7 @@ void free_dma(unsigned int channel)
        /* Clear the DMA Variable in the Channel */
        atomic_set(&dma_ch[channel].chan_status, 0);
 
-       pr_debug("freedma() : END \n");
+       pr_debug("freedma() : END\n");
 }
 EXPORT_SYMBOL(free_dma);
 
index a174596..e35e20f 100644 (file)
@@ -1289,44 +1289,50 @@ __initcall(gpio_register_proc);
 #endif
 
 #ifdef CONFIG_GPIOLIB
-int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio)
+static int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
        return bfin_gpio_direction_input(gpio);
 }
 
-int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
+static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
 {
        return bfin_gpio_direction_output(gpio, level);
 }
 
-int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio)
+static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio)
 {
        return bfin_gpio_get_value(gpio);
 }
 
-void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value)
 {
        return bfin_gpio_set_value(gpio, value);
 }
 
-int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio)
+static int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio)
 {
        return bfin_gpio_request(gpio, chip->label);
 }
 
-void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio)
+static void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio)
 {
        return bfin_gpio_free(gpio);
 }
 
+static int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+       return gpio + GPIO_IRQ_BASE;
+}
+
 static struct gpio_chip bfin_chip = {
-       .label                  = "Blackfin-GPIOlib",
+       .label                  = "BFIN-GPIO",
        .direction_input        = bfin_gpiolib_direction_input,
        .get                    = bfin_gpiolib_get_value,
        .direction_output       = bfin_gpiolib_direction_output,
        .set                    = bfin_gpiolib_set_value,
        .request                = bfin_gpiolib_gpio_request,
        .free                   = bfin_gpiolib_gpio_free,
+       .to_irq                 = bfin_gpiolib_gpio_to_irq,
        .base                   = 0,
        .ngpio                  = MAX_BLACKFIN_GPIOS,
 };
index 8d42b9e..30fd641 100644 (file)
@@ -64,6 +64,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
                icplb_tbl[cpu][i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
        }
 
+#ifdef CONFIG_ROMKERNEL
+       /* Cover kernel XIP flash area */
+       addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1);
+       dcplb_tbl[cpu][i_d].addr = addr;
+       dcplb_tbl[cpu][i_d++].data = d_data | CPLB_USER_RD;
+       icplb_tbl[cpu][i_i].addr = addr;
+       icplb_tbl[cpu][i_i++].data = i_data | CPLB_USER_RD;
+#endif
+
        /* Cover L1 memory.  One 4M area for code and data each is enough.  */
 #if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
        dcplb_tbl[cpu][i_d].addr = get_l1_data_a_start_cpu(cpu);
index 930c01c..87b25b1 100644 (file)
@@ -31,6 +31,12 @@ int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS];
 int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS];
 int nr_cplb_flush[NR_CPUS];
 
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+#define MGR_ATTR __attribute__((l1_text))
+#else
+#define MGR_ATTR
+#endif
+
 /*
  * Given the contents of the status register, return the index of the
  * CPLB that caused the fault.
@@ -59,7 +65,7 @@ static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS];
 /*
  * Find an ICPLB entry to be evicted and return its index.
  */
-static int evict_one_icplb(unsigned int cpu)
+MGR_ATTR static int evict_one_icplb(unsigned int cpu)
 {
        int i;
        for (i = first_switched_icplb; i < MAX_CPLBS; i++)
@@ -74,7 +80,7 @@ static int evict_one_icplb(unsigned int cpu)
        return i;
 }
 
-static int evict_one_dcplb(unsigned int cpu)
+MGR_ATTR static int evict_one_dcplb(unsigned int cpu)
 {
        int i;
        for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
@@ -89,7 +95,7 @@ static int evict_one_dcplb(unsigned int cpu)
        return i;
 }
 
-static noinline int dcplb_miss(unsigned int cpu)
+MGR_ATTR static noinline int dcplb_miss(unsigned int cpu)
 {
        unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
        int status = bfin_read_DCPLB_STATUS();
@@ -114,10 +120,15 @@ static noinline int dcplb_miss(unsigned int cpu)
                d_data = L2_DMEMORY;
        } else if (addr >= physical_mem_end) {
                if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
-                       addr &= ~(4 * 1024 * 1024 - 1);
-                       d_data &= ~PAGE_SIZE_4KB;
-                       d_data |= PAGE_SIZE_4MB;
-                       d_data |= CPLB_USER_RD | CPLB_USER_WR;
+                       mask = current_rwx_mask[cpu];
+                       if (mask) {
+                               int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
+                               int idx = page >> 5;
+                               int bit = 1 << (page & 31);
+
+                               if (mask[idx] & bit)
+                                       d_data |= CPLB_USER_RD;
+                       }
                } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
                    && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
                        addr &= ~(1 * 1024 * 1024 - 1);
@@ -126,7 +137,9 @@ static noinline int dcplb_miss(unsigned int cpu)
                } else
                        return CPLB_PROT_VIOL;
        } else if (addr >= _ramend) {
-           d_data |= CPLB_USER_RD | CPLB_USER_WR;
+               d_data |= CPLB_USER_RD | CPLB_USER_WR;
+               if (reserved_mem_dcache_on)
+                       d_data |= CPLB_L1_CHBL;
        } else {
                mask = current_rwx_mask[cpu];
                if (mask) {
@@ -156,7 +169,7 @@ static noinline int dcplb_miss(unsigned int cpu)
        return 0;
 }
 
-static noinline int icplb_miss(unsigned int cpu)
+MGR_ATTR static noinline int icplb_miss(unsigned int cpu)
 {
        unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
        int status = bfin_read_ICPLB_STATUS();
@@ -204,10 +217,19 @@ static noinline int icplb_miss(unsigned int cpu)
                i_data = L2_IMEMORY;
        } else if (addr >= physical_mem_end) {
                if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
-                       addr &= ~(4 * 1024 * 1024 - 1);
-                       i_data &= ~PAGE_SIZE_4KB;
-                       i_data |= PAGE_SIZE_4MB;
-                       i_data |= CPLB_USER_RD;
+                       if (!(status & FAULT_USERSUPV)) {
+                               unsigned long *mask = current_rwx_mask[cpu];
+
+                               if (mask) {
+                                       int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
+                                       int idx = page >> 5;
+                                       int bit = 1 << (page & 31);
+
+                                       mask += 2 * page_mask_nelts;
+                                       if (mask[idx] & bit)
+                                               i_data |= CPLB_USER_RD;
+                               }
+                       }
                } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
                    && (status & FAULT_USERSUPV)) {
                        addr &= ~(1 * 1024 * 1024 - 1);
@@ -217,6 +239,8 @@ static noinline int icplb_miss(unsigned int cpu)
                    return CPLB_PROT_VIOL;
        } else if (addr >= _ramend) {
                i_data |= CPLB_USER_RD;
+               if (reserved_mem_icache_on)
+                       i_data |= CPLB_L1_CHBL;
        } else {
                /*
                 * Two cases to distinguish - a supervisor access must
@@ -251,7 +275,7 @@ static noinline int icplb_miss(unsigned int cpu)
        return 0;
 }
 
-static noinline int dcplb_protection_fault(unsigned int cpu)
+MGR_ATTR static noinline int dcplb_protection_fault(unsigned int cpu)
 {
        int status = bfin_read_DCPLB_STATUS();
 
@@ -271,7 +295,7 @@ static noinline int dcplb_protection_fault(unsigned int cpu)
        return CPLB_PROT_VIOL;
 }
 
-int cplb_hdr(int seqstat, struct pt_regs *regs)
+MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs)
 {
        int cause = seqstat & 0x3f;
        unsigned int cpu = raw_smp_processor_id();
index 282a791..bfe75af 100644 (file)
@@ -56,6 +56,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
                i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB;
        }
 
+#ifdef CONFIG_ROMKERNEL
+       /* Cover kernel XIP flash area */
+       addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1);
+       d_tbl[i_d].addr = addr;
+       d_tbl[i_d++].data = SDRAM_DGENERIC | PAGE_SIZE_4MB;
+       i_tbl[i_i].addr = addr;
+       i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB;
+#endif
+
        /* Cover L1 memory.  One 4M area for code and data each is enough.  */
        if (cpu == 0) {
                if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) {
index e937f32..04ddcfe 100644 (file)
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent);
 void __dma_sync(dma_addr_t addr, size_t size,
                enum dma_data_direction dir)
 {
-       _dma_sync(addr, size, dir);
+       __dma_sync_inline(addr, size, dir);
 }
 EXPORT_SYMBOL(__dma_sync);
 
index f27dc22..686478f 100644 (file)
@@ -44,7 +44,7 @@ ENTRY(_ret_from_fork)
        sti r4;
 #endif /* CONFIG_IPIPE */
        SP += -12;
-       call _schedule_tail;
+       pseudo_long_call _schedule_tail, p5;
        SP += 12;
        r0 = [sp + PT_IPEND];
        cc = bittst(r0,1);
@@ -79,7 +79,7 @@ ENTRY(_sys_vfork)
        r0 += 24;
        [--sp] = rets;
        SP += -12;
-       call _bfin_vfork;
+       pseudo_long_call _bfin_vfork, p2;
        SP += 12;
        rets = [sp++];
        rts;
@@ -90,7 +90,7 @@ ENTRY(_sys_clone)
        r0 += 24;
        [--sp] = rets;
        SP += -12;
-       call _bfin_clone;
+       pseudo_long_call _bfin_clone, p2;
        SP += 12;
        rets = [sp++];
        rts;
@@ -101,7 +101,7 @@ ENTRY(_sys_rt_sigreturn)
        r0 += 24;
        [--sp] = rets;
        SP += -12;
-       call _do_rt_sigreturn;
+       pseudo_long_call _do_rt_sigreturn, p2;
        SP += 12;
        rets = [sp++];
        rts;
index 76dd4fb..d66446b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * mcount and friends -- ftrace stuff
  *
- * Copyright (C) 2009 Analog Devices Inc.
+ * Copyright (C) 2009-2010 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
  * function will be waiting there.  mmmm pie.
  */
 ENTRY(__mcount)
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       /* optional micro optimization: return if stopped */
+       p1.l = _function_trace_stop;
+       p1.h = _function_trace_stop;
+       r3 = [p1];
+       cc = r3 == 0;
+       if ! cc jump _ftrace_stub (bp);
+#endif
+
        /* save third function arg early so we can do testing below */
        [--sp] = r2;
 
@@ -106,9 +115,12 @@ ENTRY(_ftrace_graph_caller)
        [--sp] = r1;
        [--sp] = rets;
 
-       /* prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) */
-       r0 = sp;
-       r1 = rets;
+       /* prepare_ftrace_return(parent, self_addr, frame_pointer) */
+       r0 = sp;        /* unsigned long *parent */
+       r1 = rets;      /* unsigned long self_addr */
+#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
+       r2 = fp;        /* unsigned long frame_pointer */
+#endif
        r0 += 16;       /* skip the 4 local regs on stack */
        r1 += -MCOUNT_INSN_SIZE;
        call _prepare_ftrace_return;
@@ -127,6 +139,9 @@ ENTRY(_return_to_handler)
        [--sp] = r1;
 
        /* get original return address */
+#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
+       r0 = fp;        /* Blackfin is sane, so omit this */
+#endif
        call _ftrace_return_to_handler;
        rets = r0;
 
index f2c85ac..a61d948 100644 (file)
@@ -16,7 +16,8 @@
  * Hook the return address and push it in the stack of return addrs
  * in current thread info.
  */
-void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+                           unsigned long frame_pointer)
 {
        struct ftrace_graph_ent trace;
        unsigned long return_hooker = (unsigned long)&return_to_handler;
@@ -24,7 +25,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
        if (unlikely(atomic_read(&current->tracing_graph_pause)))
                return;
 
-       if (ftrace_push_return_trace(*parent, self_addr, &trace.depth, 0) == -EBUSY)
+       if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
+                                    frame_pointer) == -EBUSY)
                return;
 
        trace.func = self_addr;
index 118c5b9..d3970e8 100644 (file)
@@ -28,5 +28,5 @@ EXPORT_SYMBOL(init_task);
  * "init_task" linker map entry.
  */
 union thread_union init_thread_union
-    __attribute__ ((__section__(".init_task.data"))) = {
+    __init_task_data = {
 INIT_THREAD_INFO(init_task)};
index 34c7c3e..2c501ce 100644 (file)
@@ -145,7 +145,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 #endif
 }
 
-struct hw_breakpoint {
+static struct hw_breakpoint {
        unsigned int occupied:1;
        unsigned int skip:1;
        unsigned int enabled:1;
@@ -155,7 +155,7 @@ struct hw_breakpoint {
        unsigned int addr;
 } breakinfo[HW_WATCHPOINT_NUM];
 
-int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
+static int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
        int bfin_type;
@@ -202,7 +202,7 @@ int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
        return -ENOSPC;
 }
 
-int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
+static int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
        int bfin_type;
@@ -230,7 +230,7 @@ int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
        return 0;
 }
 
-void bfin_remove_all_hw_break(void)
+static void bfin_remove_all_hw_break(void)
 {
        int breakno;
 
@@ -242,7 +242,7 @@ void bfin_remove_all_hw_break(void)
                breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
 }
 
-void bfin_correct_hw_break(void)
+static void bfin_correct_hw_break(void)
 {
        int breakno;
        unsigned int wpiactl = 0;
diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c
new file mode 100644 (file)
index 0000000..0b5f72f
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Blackfin nmi_watchdog Driver
+ *
+ * Originally based on bfin_wdt.c
+ * Copyright 2010-2010 Analog Devices Inc.
+ *             Graff Yang <graf.yang@analog.com>
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/bitops.h>
+#include <linux/hardirq.h>
+#include <linux/sysdev.h>
+#include <linux/pm.h>
+#include <linux/nmi.h>
+#include <linux/smp.h>
+#include <linux/timer.h>
+#include <asm/blackfin.h>
+#include <asm/atomic.h>
+#include <asm/cacheflush.h>
+#include <asm/bfin_watchdog.h>
+
+#define DRV_NAME "nmi-wdt"
+
+#define NMI_WDT_TIMEOUT 5          /* 5 seconds */
+#define NMI_CHECK_TIMEOUT (4 * HZ) /* 4 seconds in jiffies */
+static int nmi_wdt_cpu = 1;
+
+static unsigned int timeout = NMI_WDT_TIMEOUT;
+static int nmi_active;
+
+static unsigned short wdoga_ctl;
+static unsigned int wdoga_cnt;
+static struct corelock_slot saved_corelock;
+static atomic_t nmi_touched[NR_CPUS];
+static struct timer_list ntimer;
+
+enum {
+       COREA_ENTER_NMI = 0,
+       COREA_EXIT_NMI,
+       COREB_EXIT_NMI,
+
+       NMI_EVENT_NR,
+};
+static unsigned long nmi_event __attribute__ ((__section__(".l2.bss")));
+
+/* we are in nmi, non-atomic bit ops is safe */
+static inline void set_nmi_event(int event)
+{
+       __set_bit(event, &nmi_event);
+}
+
+static inline void wait_nmi_event(int event)
+{
+       while (!test_bit(event, &nmi_event))
+               barrier();
+       __clear_bit(event, &nmi_event);
+}
+
+static inline void send_corea_nmi(void)
+{
+       wdoga_ctl = bfin_read_WDOGA_CTL();
+       wdoga_cnt = bfin_read_WDOGA_CNT();
+
+       bfin_write_WDOGA_CTL(WDEN_DISABLE);
+       bfin_write_WDOGA_CNT(0);
+       bfin_write_WDOGA_CTL(WDEN_ENABLE | ICTL_NMI);
+}
+
+static inline void restore_corea_nmi(void)
+{
+       bfin_write_WDOGA_CTL(WDEN_DISABLE);
+       bfin_write_WDOGA_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE);
+
+       bfin_write_WDOGA_CNT(wdoga_cnt);
+       bfin_write_WDOGA_CTL(wdoga_ctl);
+}
+
+static inline void save_corelock(void)
+{
+       saved_corelock = corelock;
+       corelock.lock = 0;
+}
+
+static inline void restore_corelock(void)
+{
+       corelock = saved_corelock;
+}
+
+
+static inline void nmi_wdt_keepalive(void)
+{
+       bfin_write_WDOGB_STAT(0);
+}
+
+static inline void nmi_wdt_stop(void)
+{
+       bfin_write_WDOGB_CTL(WDEN_DISABLE);
+}
+
+/* before calling this function, you must stop the WDT */
+static inline void nmi_wdt_clear(void)
+{
+       /* clear TRO bit, disable event generation */
+       bfin_write_WDOGB_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE);
+}
+
+static inline void nmi_wdt_start(void)
+{
+       bfin_write_WDOGB_CTL(WDEN_ENABLE | ICTL_NMI);
+}
+
+static inline int nmi_wdt_running(void)
+{
+       return ((bfin_read_WDOGB_CTL() & WDEN_MASK) != WDEN_DISABLE);
+}
+
+static inline int nmi_wdt_set_timeout(unsigned long t)
+{
+       u32 cnt, max_t, sclk;
+       int run;
+
+       sclk = get_sclk();
+       max_t = -1 / sclk;
+       cnt = t * sclk;
+       if (t > max_t) {
+               pr_warning("NMI: timeout value is too large\n");
+               return -EINVAL;
+       }
+
+       run = nmi_wdt_running();
+       nmi_wdt_stop();
+       bfin_write_WDOGB_CNT(cnt);
+       if (run)
+               nmi_wdt_start();
+
+       timeout = t;
+
+       return 0;
+}
+
+int check_nmi_wdt_touched(void)
+{
+       unsigned int this_cpu = smp_processor_id();
+       unsigned int cpu;
+
+       cpumask_t mask = cpu_online_map;
+
+       if (!atomic_read(&nmi_touched[this_cpu]))
+               return 0;
+
+       atomic_set(&nmi_touched[this_cpu], 0);
+
+       cpu_clear(this_cpu, mask);
+       for_each_cpu_mask(cpu, mask) {
+               invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]),
+                               (unsigned long)(&nmi_touched[cpu]));
+               if (!atomic_read(&nmi_touched[cpu]))
+                       return 0;
+               atomic_set(&nmi_touched[cpu], 0);
+       }
+
+       return 1;
+}
+
+static void nmi_wdt_timer(unsigned long data)
+{
+       if (check_nmi_wdt_touched())
+               nmi_wdt_keepalive();
+
+       mod_timer(&ntimer, jiffies + NMI_CHECK_TIMEOUT);
+}
+
+static int __init init_nmi_wdt(void)
+{
+       nmi_wdt_set_timeout(timeout);
+       nmi_wdt_start();
+       nmi_active = true;
+
+       init_timer(&ntimer);
+       ntimer.function = nmi_wdt_timer;
+       ntimer.expires = jiffies + NMI_CHECK_TIMEOUT;
+       add_timer(&ntimer);
+
+       pr_info("nmi_wdt: initialized: timeout=%d sec\n", timeout);
+       return 0;
+}
+device_initcall(init_nmi_wdt);
+
+void touch_nmi_watchdog(void)
+{
+       atomic_set(&nmi_touched[smp_processor_id()], 1);
+}
+
+/* Suspend/resume support */
+#ifdef CONFIG_PM
+static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state)
+{
+       nmi_wdt_stop();
+       return 0;
+}
+
+static int nmi_wdt_resume(struct sys_device *dev)
+{
+       if (nmi_active)
+               nmi_wdt_start();
+       return 0;
+}
+
+static struct sysdev_class nmi_sysclass = {
+       .name           = DRV_NAME,
+       .resume         = nmi_wdt_resume,
+       .suspend        = nmi_wdt_suspend,
+};
+
+static struct sys_device device_nmi_wdt = {
+       .id     = 0,
+       .cls    = &nmi_sysclass,
+};
+
+static int __init init_nmi_wdt_sysfs(void)
+{
+       int error;
+
+       if (!nmi_active)
+               return 0;
+
+       error = sysdev_class_register(&nmi_sysclass);
+       if (!error)
+               error = sysdev_register(&device_nmi_wdt);
+       return error;
+}
+late_initcall(init_nmi_wdt_sysfs);
+
+#endif /* CONFIG_PM */
+
+
+asmlinkage notrace void do_nmi(struct pt_regs *fp)
+{
+       unsigned int cpu = smp_processor_id();
+       nmi_enter();
+
+       cpu_pda[cpu].__nmi_count += 1;
+
+       if (cpu == nmi_wdt_cpu) {
+               /* CoreB goes here first */
+
+               /* reload the WDOG_STAT */
+               nmi_wdt_keepalive();
+
+               /* clear nmi interrupt for CoreB */
+               nmi_wdt_stop();
+               nmi_wdt_clear();
+
+               /* trigger NMI interrupt of CoreA */
+               send_corea_nmi();
+
+               /* waiting CoreB to enter NMI */
+               wait_nmi_event(COREA_ENTER_NMI);
+
+               /* recover WDOGA's settings */
+               restore_corea_nmi();
+
+               save_corelock();
+
+               /* corelock is save/cleared, CoreA is dummping messages */
+
+               wait_nmi_event(COREA_EXIT_NMI);
+       } else {
+               /* OK, CoreA entered NMI */
+               set_nmi_event(COREA_ENTER_NMI);
+       }
+
+       pr_emerg("\nNMI Watchdog detected LOCKUP, dump for CPU %d\n", cpu);
+       dump_bfin_process(fp);
+       dump_bfin_mem(fp);
+       show_regs(fp);
+       dump_bfin_trace_buffer();
+       show_stack(current, (unsigned long *)fp);
+
+       if (cpu == nmi_wdt_cpu) {
+               pr_emerg("This fault is not recoverable, sorry!\n");
+
+               /* CoreA dump finished, restore the corelock */
+               restore_corelock();
+
+               set_nmi_event(COREB_EXIT_NMI);
+       } else {
+               /* CoreB dump finished, notice the CoreA we are done */
+               set_nmi_event(COREA_EXIT_NMI);
+
+               /* synchronize with CoreA */
+               wait_nmi_event(COREB_EXIT_NMI);
+       }
+
+       nmi_exit();
+}
index b56b0e4..29705ce 100644 (file)
@@ -98,13 +98,6 @@ void cpu_idle(void)
        }
 }
 
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
-{
-       return 1;
-}
-
 /*
  * This gets run with P1 containing the
  * function to call, and R1 containing
index 65567dc..43eb969 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- * these modifications are Copyright 2004-2009 Analog Devices Inc.
+ * these modifications are Copyright 2004-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2
  */
@@ -9,10 +9,13 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/elf.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/regset.h>
 #include <linux/signal.h>
+#include <linux/tracehook.h>
 #include <linux/uaccess.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <asm/mem_map.h>
 
-#define TEXT_OFFSET 0
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
  */
 
-/* determines which bits in the SYSCFG reg the user has access to. */
-/* 1 = access 0 = no access */
-#define SYSCFG_MASK 0x0007     /* SYSCFG reg */
-/* sets the trace bits. */
-#define TRACE_BITS 0x0001
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-
-/*
- * Get the address of the live pt_regs for the specified task.
- * These are saved onto the top kernel stack when the process
- * is not running.
- *
- * Note: if a user thread is execve'd from kernel space, the
- * kernel stack will not be empty on entry to the kernel, so
- * ptracing these tasks will fail.
- */
-static inline struct pt_regs *get_user_regs(struct task_struct *task)
-{
-       return (struct pt_regs *)
-           ((unsigned long)task_stack_page(task) +
-            (THREAD_SIZE - sizeof(struct pt_regs)));
-}
-
-/*
- * Get all user integer registers.
- */
-static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
-{
-       struct pt_regs regs;
-       memcpy(&regs, get_user_regs(tsk), sizeof(regs));
-       regs.usp = tsk->thread.usp;
-       return copy_to_user(uregs, &regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
-}
-
-/* Mapping from PT_xxx to the stack offset at which the register is
- * saved.  Notice that usp has no stack-slot and needs to be treated
- * specially (see get_reg/put_reg below).
- */
-
 /*
  * Get contents of register REGNO in task TASK.
  */
-static inline long get_reg(struct task_struct *task, int regno)
+static inline long
+get_reg(struct task_struct *task, long regno, unsigned long __user *datap)
 {
-       unsigned char *reg_ptr;
+       long tmp;
+       struct pt_regs *regs = task_pt_regs(task);
 
-       struct pt_regs *regs =
-           (struct pt_regs *)((unsigned long)task_stack_page(task) +
-                              (THREAD_SIZE - sizeof(struct pt_regs)));
-       reg_ptr = (char *)regs;
+       if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+               return -EIO;
 
        switch (regno) {
+       case PT_TEXT_ADDR:
+               tmp = task->mm->start_code;
+               break;
+       case PT_TEXT_END_ADDR:
+               tmp = task->mm->end_code;
+               break;
+       case PT_DATA_ADDR:
+               tmp = task->mm->start_data;
+               break;
        case PT_USP:
-               return task->thread.usp;
+               tmp = task->thread.usp;
+               break;
        default:
-               if (regno <= 216)
-                       return *(long *)(reg_ptr + regno);
+               if (regno < sizeof(*regs)) {
+                       void *reg_ptr = regs;
+                       tmp = *(long *)(reg_ptr + regno);
+               } else
+                       return -EIO;
        }
-       /* slight mystery ... never seems to come here but kernel misbehaves without this code! */
 
-       printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
-       return 0;
+       return put_user(tmp, datap);
 }
 
 /*
  * Write contents of register REGNO in task TASK.
  */
 static inline int
-put_reg(struct task_struct *task, int regno, unsigned long data)
+put_reg(struct task_struct *task, long regno, unsigned long data)
 {
-       char *reg_ptr;
+       struct pt_regs *regs = task_pt_regs(task);
 
-       struct pt_regs *regs =
-           (struct pt_regs *)((unsigned long)task_stack_page(task) +
-                              (THREAD_SIZE - sizeof(struct pt_regs)));
-       reg_ptr = (char *)regs;
+       if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+               return -EIO;
 
        switch (regno) {
        case PT_PC:
@@ -125,10 +95,18 @@ put_reg(struct task_struct *task, int regno, unsigned long data)
                regs->usp = data;
                task->thread.usp = data;
                break;
+       case PT_SYSCFG: /* don't let userspace screw with this */
+               if ((data & ~1) != 0x6)
+                       pr_warning("ptrace: ignore syscfg write of %#lx\n", data);
+               break;          /* regs->syscfg = data; break; */
        default:
-               if (regno <= 216)
-                       *(long *)(reg_ptr + regno) = data;
+               if (regno < sizeof(*regs)) {
+                       void *reg_offset = regs;
+                       *(long *)(reg_offset + regno) = data;
+               }
+               /* Ignore writes to pseudo registers */
        }
+
        return 0;
 }
 
@@ -160,24 +138,98 @@ static inline int is_user_addr_valid(struct task_struct *child,
        return -EIO;
 }
 
-void ptrace_enable(struct task_struct *child)
+/*
+ * retrieve the contents of Blackfin userspace general registers
+ */
+static int genregs_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
 {
-       unsigned long tmp;
-       tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
-       put_reg(child, PT_SYSCFG, tmp);
+       struct pt_regs *regs = task_pt_regs(target);
+       int ret;
+
+       /* This sucks ... */
+       regs->usp = target->thread.usp;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 regs, 0, sizeof(*regs));
+       if (ret < 0)
+               return ret;
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       sizeof(*regs), -1);
 }
 
 /*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
+ * update the contents of the Blackfin userspace general registers
+ */
+static int genregs_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
+{
+       struct pt_regs *regs = task_pt_regs(target);
+       int ret;
+
+       /* Don't let people set SYSCFG (it's at the end of pt_regs) */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                regs, 0, PT_SYSCFG);
+       if (ret < 0)
+               return ret;
+
+       /* This sucks ... */
+       target->thread.usp = regs->usp;
+       /* regs->retx = regs->pc; */
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       PT_SYSCFG, -1);
+}
+
+/*
+ * Define the register sets available on the Blackfin under Linux
  */
-void ptrace_disable(struct task_struct *child)
+enum bfin_regset {
+       REGSET_GENERAL,
+};
+
+static const struct user_regset bfin_regsets[] = {
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n              = sizeof(struct pt_regs) / sizeof(long),
+               .size           = sizeof(long),
+               .align          = sizeof(long),
+               .get            = genregs_get,
+               .set            = genregs_set,
+       },
+};
+
+static const struct user_regset_view user_bfin_native_view = {
+       .name      = "Blackfin",
+       .e_machine = EM_BLACKFIN,
+       .regsets   = bfin_regsets,
+       .n         = ARRAY_SIZE(bfin_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &user_bfin_native_view;
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+       struct pt_regs *regs = task_pt_regs(child);
+       regs->syscfg |= SYSCFG_SSSTEP;
+
+       set_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+void user_disable_single_step(struct task_struct *child)
 {
-       unsigned long tmp;
-       /* make sure the single step bit is not set. */
-       tmp = get_reg(child, PT_SYSCFG) & ~TRACE_BITS;
-       put_reg(child, PT_SYSCFG, tmp);
+       struct pt_regs *regs = task_pt_regs(child);
+       regs->syscfg &= ~SYSCFG_SSSTEP;
+
+       clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -240,40 +292,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
                }
 
-               /* read the word at location addr in the USER area. */
-       case PTRACE_PEEKUSR:
-               {
-                       unsigned long tmp;
-                       ret = -EIO;
-                       tmp = 0;
-                       if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
-                               printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
-                                                   "0 - %x sizeof(pt_regs) is %lx\n",
-                                    (int)addr, sizeof(struct pt_regs));
-                               break;
-                       }
-                       if (addr == sizeof(struct pt_regs)) {
-                               /* PT_TEXT_ADDR */
-                               tmp = child->mm->start_code + TEXT_OFFSET;
-                       } else if (addr == (sizeof(struct pt_regs) + 4)) {
-                               /* PT_TEXT_END_ADDR */
-                               tmp = child->mm->end_code;
-                       } else if (addr == (sizeof(struct pt_regs) + 8)) {
-                               /* PT_DATA_ADDR */
-                               tmp = child->mm->start_data;
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-                       } else if (addr == (sizeof(struct pt_regs) + 12)) {
-                               goto case_PTRACE_GETFDPIC_EXEC;
-                       } else if (addr == (sizeof(struct pt_regs) + 16)) {
-                               goto case_PTRACE_GETFDPIC_INTERP;
-#endif
-                       } else {
-                               tmp = get_reg(child, addr);
-                       }
-                       ret = put_user(tmp, datap);
-                       break;
-               }
-
 #ifdef CONFIG_BINFMT_ELF_FDPIC
        case PTRACE_GETFDPIC: {
                unsigned long tmp = 0;
@@ -336,78 +354,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
                }
 
-       case PTRACE_POKEUSR:    /* write the word at location addr in the USER area */
-               ret = -EIO;
-               if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
-                       printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
-                       break;
-               }
-
-               if (addr >= (sizeof(struct pt_regs))) {
-                       ret = 0;
-                       break;
-               }
-               if (addr == PT_SYSCFG) {
-                       data &= SYSCFG_MASK;
-                       data |= get_reg(child, PT_SYSCFG);
+       case PTRACE_PEEKUSR:
+               switch (addr) {
+#ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
+               case PT_FDPIC_EXEC:   goto case_PTRACE_GETFDPIC_EXEC;
+               case PT_FDPIC_INTERP: goto case_PTRACE_GETFDPIC_INTERP;
+#endif
+               default:
+                       ret = get_reg(child, addr, datap);
                }
-               ret = put_reg(child, addr, data);
+               pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret);
                break;
 
-       case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:       /* restart after signal. */
-               pr_debug("ptrace: syscall/cont\n");
-
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               ptrace_disable(child);
-               pr_debug("ptrace: before wake_up_process\n");
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               ptrace_disable(child);
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP: /* set the trap flag. */
-               pr_debug("ptrace: single step\n");
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               ptrace_enable(child);
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_POKEUSR:
+               ret = put_reg(child, addr, data);
+               pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret);
                break;
 
        case PTRACE_GETREGS:
-               /* Get all gp regs from the child. */
-               ret = ptrace_getregs(child, datap);
-               break;
+               pr_debug("ptrace: PTRACE_GETREGS\n");
+               return copy_regset_to_user(child, &user_bfin_native_view,
+                                          REGSET_GENERAL,
+                                          0, sizeof(struct pt_regs),
+                                          (void __user *)data);
 
        case PTRACE_SETREGS:
-               printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
-               /* Set all gp regs in the child. */
-               ret = 0;
-               break;
+               pr_debug("ptrace: PTRACE_SETREGS\n");
+               return copy_regset_from_user(child, &user_bfin_native_view,
+                                            REGSET_GENERAL,
+                                            0, sizeof(struct pt_regs),
+                                            (const void __user *)data);
 
        default:
                ret = ptrace_request(child, request, addr, data);
@@ -417,27 +393,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        return ret;
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-
-       if (!(current->ptrace & PT_PTRACED))
-               return;
-
-       /* the 0x80 provides a way for the tracing parent to distinguish
-        * between a syscall stop and SIGTRAP delivery
-        */
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                ? 0x80 : 0));
-
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+       int ret = 0;
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(regs);
+
+       return ret;
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+       int step;
+
+       step = test_thread_flag(TIF_SINGLESTEP);
+       if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, step);
 }
index 95448ae..8e2efce 100644 (file)
@@ -220,6 +220,16 @@ void __init bfin_relocate_l1_mem(void)
                memcpy(_stext_l2, _l2_lma, l2_len);
 }
 
+#ifdef CONFIG_ROMKERNEL
+void __init bfin_relocate_xip_data(void)
+{
+       early_shadow_stamp();
+
+       memcpy(_sdata, _data_lma, (unsigned long)_data_len - THREAD_SIZE + sizeof(struct thread_info));
+       memcpy(_sinitdata, _init_data_lma, (unsigned long)_init_data_len);
+}
+#endif
+
 /* add_memory_region to memmap */
 static void __init add_memory_region(unsigned long long start,
                              unsigned long long size, int type)
@@ -504,7 +514,7 @@ static __init void memory_setup(void)
 #endif
        unsigned long max_mem;
 
-       _rambase = (unsigned long)_stext;
+       _rambase = CONFIG_BOOT_LOAD;
        _ramstart = (unsigned long)_end;
 
        if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) {
@@ -597,7 +607,12 @@ static __init void memory_setup(void)
        }
 
 #ifdef CONFIG_MPU
+#if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM)
+       page_mask_nelts = (((_ramend + ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE -
+                                       ASYNC_BANK0_BASE) >> PAGE_SHIFT) + 31) / 32;
+#else
        page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
+#endif
        page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
 #endif
 
@@ -630,7 +645,7 @@ static __init void memory_setup(void)
                __bss_start, __bss_stop,
                _sdata, _edata,
                (void *)&init_thread_union,
-               (void *)((int)(&init_thread_union) + 0x2000),
+               (void *)((int)(&init_thread_union) + THREAD_SIZE),
                __init_begin, __init_end,
                (void *)_ramstart, (void *)memory_end
 #ifdef CONFIG_MTD_UCLINUX
@@ -792,10 +807,17 @@ static inline int __init get_mem_size(void)
        BUG();
 }
 
+__attribute__((weak))
+void __init native_machine_early_platform_add_devices(void)
+{
+}
+
 void __init setup_arch(char **cmdline_p)
 {
        unsigned long sclk, cclk;
 
+       native_machine_early_platform_add_devices();
+
        enable_shadow_console();
 
        /* Check to make sure we are running on the right processor */
@@ -1217,10 +1239,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                   dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS,
                   BFIN_DLINES);
 #ifdef __ARCH_SYNC_CORE_DCACHE
-       seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count);
+       seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", dcache_invld_count[cpu_num]);
 #endif
 #ifdef __ARCH_SYNC_CORE_ICACHE
-       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count);
+       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", icache_invld_count[cpu_num]);
 #endif
 
        if (cpu_num != num_possible_cpus() - 1)
@@ -1249,8 +1271,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n",
                 physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);
        seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n",
-               ((int)memory_end - (int)_stext) >> 10,
-               _stext,
+               ((int)memory_end - (int)_rambase) >> 10,
+               (void *)_rambase,
                (void *)memory_end);
        seq_printf(m, "\n");
 
index e0fd63e..d536f35 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2009 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later
  */
@@ -17,6 +17,7 @@
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
 #include <asm/fixed_code.h>
+#include <asm/syscall.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -50,6 +51,9 @@ rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *p
        unsigned long usp = 0;
        int err = 0;
 
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
 #define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
 
        /* restore passed registers */
@@ -206,16 +210,6 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
        regs->r1 = (unsigned long)(&frame->info);
        regs->r2 = (unsigned long)(&frame->uc);
 
-       /*
-        * Clear the trace flag when entering the signal handler, but
-        * notify any tracer that was single-stepping it. The tracer
-        * may want to single-step inside the handler too.
-        */
-       if (regs->syscfg & TRACE_BITS) {
-               regs->syscfg &= ~TRACE_BITS;
-               ptrace_notify(SIGTRAP);
-       }
-
        return 0;
 
  give_sigsegv:
@@ -247,6 +241,11 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
                regs->r0 = regs->orig_r0;
                regs->pc -= 2;
                break;
+
+       case -ERESTART_RESTARTBLOCK:
+               regs->p0 = __NR_restart_syscall;
+               regs->pc -= 2;
+               break;
        }
 }
 
@@ -315,6 +314,9 @@ asmlinkage void do_signal(struct pt_regs *regs)
                         * clear the TIF_RESTORE_SIGMASK flag */
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                                clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       tracehook_signal_handler(signr, &info, &ka, regs,
+                               test_thread_flag(TIF_SINGLESTEP));
                }
 
                return;
index 17c38c5..cb7a01d 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/blackfin.h>
 #include <asm/time.h>
 #include <asm/gptimers.h>
+#include <asm/nmi.h>
 
 /* Accelerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
 
 static notrace cycle_t bfin_read_cycles(struct clocksource *cs)
 {
+#ifdef CONFIG_CPU_FREQ
        return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
+#else
+       return get_cycles();
+#endif
 }
 
 static struct clocksource bfin_cs_cycles = {
@@ -132,7 +137,6 @@ static int __init bfin_cs_gptimer0_init(void)
 # define bfin_cs_gptimer0_init()
 #endif
 
-
 #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
 /* prefer to use cycles since it has higher rating */
 notrace unsigned long long sched_clock(void)
@@ -145,47 +149,8 @@ notrace unsigned long long sched_clock(void)
 }
 #endif
 
-#ifdef CONFIG_CORE_TIMER_IRQ_L1
-__attribute__((l1_text))
-#endif
-irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-static int bfin_timer_set_next_event(unsigned long, \
-               struct clock_event_device *);
-
-static void bfin_timer_set_mode(enum clock_event_mode, \
-               struct clock_event_device *);
-
-static struct clock_event_device clockevent_bfin = {
-#if defined(CONFIG_TICKSOURCE_GPTMR0)
-       .name           = "bfin_gptimer0",
-       .rating         = 300,
-       .irq            = IRQ_TIMER0,
-#else
-       .name           = "bfin_core_timer",
-       .rating         = 350,
-       .irq            = IRQ_CORETMR,
-#endif
-       .shift          = 32,
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_next_event = bfin_timer_set_next_event,
-       .set_mode       = bfin_timer_set_mode,
-};
-
-static struct irqaction bfin_timer_irq = {
-#if defined(CONFIG_TICKSOURCE_GPTMR0)
-       .name           = "Blackfin GPTimer0",
-#else
-       .name           = "Blackfin CoreTimer",
-#endif
-       .flags          = IRQF_DISABLED | IRQF_TIMER | \
-                         IRQF_IRQPOLL | IRQF_PERCPU,
-       .handler        = timer_interrupt,
-       .dev_id         = &clockevent_bfin,
-};
-
 #if defined(CONFIG_TICKSOURCE_GPTMR0)
-static int bfin_timer_set_next_event(unsigned long cycles,
+static int bfin_gptmr0_set_next_event(unsigned long cycles,
                                      struct clock_event_device *evt)
 {
        disable_gptimers(TIMER0bit);
@@ -196,7 +161,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
        return 0;
 }
 
-static void bfin_timer_set_mode(enum clock_event_mode mode,
+static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
        switch (mode) {
@@ -224,25 +189,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
        }
 }
 
-static void bfin_timer_ack(void)
+static void bfin_gptmr0_ack(void)
 {
        set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
 }
 
-static void __init bfin_timer_init(void)
+static void __init bfin_gptmr0_init(void)
 {
        disable_gptimers(TIMER0bit);
 }
 
-static unsigned long  __init bfin_clockevent_check(void)
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+__attribute__((l1_text))
+#endif
+irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
 {
-       setup_irq(IRQ_TIMER0, &bfin_timer_irq);
-       return get_sclk();
+       struct clock_event_device *evt = dev_id;
+       smp_mb();
+       evt->event_handler(evt);
+       bfin_gptmr0_ack();
+       return IRQ_HANDLED;
 }
 
-#else /* CONFIG_TICKSOURCE_CORETMR */
+static struct irqaction gptmr0_irq = {
+       .name           = "Blackfin GPTimer0",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | \
+                         IRQF_IRQPOLL | IRQF_PERCPU,
+       .handler        = bfin_gptmr0_interrupt,
+};
 
-static int bfin_timer_set_next_event(unsigned long cycles,
+static struct clock_event_device clockevent_gptmr0 = {
+       .name           = "bfin_gptimer0",
+       .rating         = 300,
+       .irq            = IRQ_TIMER0,
+       .shift          = 32,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_next_event = bfin_gptmr0_set_next_event,
+       .set_mode       = bfin_gptmr0_set_mode,
+};
+
+static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
+{
+       unsigned long clock_tick;
+
+       clock_tick = get_sclk();
+       evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
+       evt->max_delta_ns = clockevent_delta2ns(-1, evt);
+       evt->min_delta_ns = clockevent_delta2ns(100, evt);
+
+       evt->cpumask = cpumask_of(0);
+
+       clockevents_register_device(evt);
+}
+#endif /* CONFIG_TICKSOURCE_GPTMR0 */
+
+#if defined(CONFIG_TICKSOURCE_CORETMR)
+/* per-cpu local core timer */
+static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
+
+static int bfin_coretmr_set_next_event(unsigned long cycles,
                                struct clock_event_device *evt)
 {
        bfin_write_TCNTL(TMPWR);
@@ -253,7 +258,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
        return 0;
 }
 
-static void bfin_timer_set_mode(enum clock_event_mode mode,
+static void bfin_coretmr_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
        switch (mode) {
@@ -285,19 +290,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
        }
 }
 
-static void bfin_timer_ack(void)
-{
-}
-
-static void __init bfin_timer_init(void)
+void bfin_coretmr_init(void)
 {
        /* power up the timer, but don't enable it just yet */
        bfin_write_TCNTL(TMPWR);
        CSYNC();
 
-       /*
-        * the TSCALE prescaler counter.
-        */
+       /* the TSCALE prescaler counter. */
        bfin_write_TSCALE(TIME_SCALE - 1);
        bfin_write_TPERIOD(0);
        bfin_write_TCOUNT(0);
@@ -305,48 +304,54 @@ static void __init bfin_timer_init(void)
        CSYNC();
 }
 
-static unsigned long  __init bfin_clockevent_check(void)
-{
-       setup_irq(IRQ_CORETMR, &bfin_timer_irq);
-       return get_cclk() / TIME_SCALE;
-}
-
-void __init setup_core_timer(void)
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+__attribute__((l1_text))
+#endif
+irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
 {
-       bfin_timer_init();
-       bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL);
-}
-#endif /* CONFIG_TICKSOURCE_GPTMR0 */
+       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
 
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = dev_id;
        smp_mb();
        evt->event_handler(evt);
-       bfin_timer_ack();
-       return IRQ_HANDLED;
-}
-
-static int __init bfin_clockevent_init(void)
-{
-       unsigned long timer_clk;
 
-       timer_clk = bfin_clockevent_check();
+       touch_nmi_watchdog();
 
-       bfin_timer_init();
+       return IRQ_HANDLED;
+}
 
-       clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift);
-       clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin);
-       clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin);
-       clockevent_bfin.cpumask = cpumask_of(0);
-       clockevents_register_device(&clockevent_bfin);
+static struct irqaction coretmr_irq = {
+       .name           = "Blackfin CoreTimer",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | \
+                         IRQF_IRQPOLL | IRQF_PERCPU,
+       .handler        = bfin_coretmr_interrupt,
+};
 
-       return 0;
+void bfin_coretmr_clockevent_init(void)
+{
+       unsigned long clock_tick;
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
+
+       evt->name = "bfin_core_timer";
+       evt->rating = 350;
+       evt->irq = -1;
+       evt->shift = 32;
+       evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       evt->set_next_event = bfin_coretmr_set_next_event;
+       evt->set_mode = bfin_coretmr_set_mode;
+
+       clock_tick = get_cclk() / TIME_SCALE;
+       evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
+       evt->max_delta_ns = clockevent_delta2ns(-1, evt);
+       evt->min_delta_ns = clockevent_delta2ns(100, evt);
+
+       evt->cpumask = cpumask_of(cpu);
+
+       clockevents_register_device(evt);
 }
+#endif /* CONFIG_TICKSOURCE_CORETMR */
+
 
 void __init time_init(void)
 {
@@ -370,5 +375,21 @@ void __init time_init(void)
 
        bfin_cs_cycles_init();
        bfin_cs_gptimer0_init();
-       bfin_clockevent_init();
+
+#if defined(CONFIG_TICKSOURCE_CORETMR)
+       bfin_coretmr_init();
+       setup_irq(IRQ_CORETMR, &coretmr_irq);
+       bfin_coretmr_clockevent_init();
+#endif
+
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
+       bfin_gptmr0_init();
+       setup_irq(IRQ_TIMER0, &gptmr0_irq);
+       gptmr0_irq.dev_id = &clockevent_gptmr0;
+       bfin_gptmr0_clockevent_init(&clockevent_gptmr0);
+#endif
+
+#if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0)
+# error at least one clock event device is required
+#endif
 }
index d3cbcd6..ba70c4b 100644 (file)
@@ -138,6 +138,12 @@ static void decode_address(char *buf, unsigned long address)
                if (!mm)
                        continue;
 
+               if (!down_read_trylock(&mm->mmap_sem)) {
+                       if (!in_atomic)
+                               mmput(mm);
+                       continue;
+               }
+
                for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
                        struct vm_area_struct *vma;
 
@@ -177,6 +183,7 @@ static void decode_address(char *buf, unsigned long address)
                                        sprintf(buf, "[ %s vma:0x%lx-0x%lx]",
                                                name, vma->vm_start, vma->vm_end);
 
+                               up_read(&mm->mmap_sem);
                                if (!in_atomic)
                                        mmput(mm);
 
@@ -186,11 +193,16 @@ static void decode_address(char *buf, unsigned long address)
                                goto done;
                        }
                }
+
+               up_read(&mm->mmap_sem);
                if (!in_atomic)
                        mmput(mm);
        }
 
-       /* we were unable to find this address anywhere */
+       /*
+        * we were unable to find this address anywhere,
+        * or some MMs were skipped because they were in use.
+        */
        sprintf(buf, "/* kernel dynamic memory */");
 
 done:
@@ -248,9 +260,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
        int j;
 #endif
-#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
        unsigned int cpu = raw_smp_processor_id();
-#endif
        const char *strerror = NULL;
        int sig = 0;
        siginfo_t info;
@@ -639,7 +649,17 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
        {
                info.si_signo = sig;
                info.si_errno = 0;
-               info.si_addr = (void __user *)fp->pc;
+               switch (trapnr) {
+               case VEC_CPLB_VL:
+               case VEC_MISALI_D:
+               case VEC_CPLB_M:
+               case VEC_CPLB_MHIT:
+                       info.si_addr = (void __user *)cpu_pda[cpu].dcplb_fault_addr;
+                       break;
+               default:
+                       info.si_addr = (void __user *)fp->pc;
+                       break;
+               }
                force_sig_info(sig, &info, current);
        }
 
@@ -712,7 +732,7 @@ static void decode_instruction(unsigned short *address)
                        verbose_printk("RTE");
                else if (opcode == 0x0025)
                        verbose_printk("EMUEXCPT");
-               else if (opcode == 0x0040 && opcode <= 0x0047)
+               else if (opcode >= 0x0040 && opcode <= 0x0047)
                        verbose_printk("STI R%i", opcode & 7);
                else if (opcode >= 0x0050 && opcode <= 0x0057)
                        verbose_printk("JUMP (P%i)", opcode & 7);
@@ -1096,7 +1116,7 @@ void dump_bfin_mem(struct pt_regs *fp)
                        /* And the last RETI points to the current userspace context */
                        if ((fp + 1)->pc >= current->mm->start_code &&
                            (fp + 1)->pc <= current->mm->end_code) {
-                               verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
+                               verbose_printk(KERN_NOTICE "It might be better to look around here :\n");
                                verbose_printk(KERN_NOTICE "-------------------------------------------\n");
                                show_regs(fp + 1);
                                verbose_printk(KERN_NOTICE "-------------------------------------------\n");
index 66799e7..984c781 100644 (file)
@@ -15,7 +15,12 @@ _jiffies = _jiffies_64;
 
 SECTIONS
 {
+#ifdef CONFIG_RAMKERNEL
        . = CONFIG_BOOT_LOAD;
+#else
+       . = CONFIG_ROM_BASE;
+#endif
+
        /* Neither the text, ro_data or bss section need to be aligned
         * So pack them back to back
         */
@@ -31,6 +36,12 @@ SECTIONS
                LOCK_TEXT
                IRQENTRY_TEXT
                KPROBES_TEXT
+#ifdef CONFIG_ROMKERNEL
+               __sinittext = .;
+               INIT_TEXT
+               __einittext = .;
+               EXIT_TEXT
+#endif
                *(.text.*)
                *(.fixup)
 
@@ -50,8 +61,14 @@ SECTIONS
 
        /* Just in case the first read only is a 32-bit access */
        RO_DATA(4)
+       __rodata_end = .;
 
+#ifdef CONFIG_ROMKERNEL
+       . = CONFIG_BOOT_LOAD;
+       .bss : AT(__rodata_end)
+#else
        .bss :
+#endif
        {
                . = ALIGN(4);
                ___bss_start = .;
@@ -67,7 +84,11 @@ SECTIONS
                ___bss_stop = .;
        }
 
+#if defined(CONFIG_ROMKERNEL)
+       .data : AT(LOADADDR(.bss) + SIZEOF(.bss))
+#else
        .data :
+#endif
        {
                __sdata = .;
                /* This gets done first, so the glob doesn't suck it in */
@@ -94,6 +115,8 @@ SECTIONS
 
                __edata = .;
        }
+       __data_lma = LOADADDR(.data);
+       __data_len = SIZEOF(.data);
 
        /* The init section should be last, so when we free it, it goes into
         * the general memory pool, and (hopefully) will decrease fragmentation
@@ -103,25 +126,58 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        ___init_begin = .;
 
+#ifdef CONFIG_RAMKERNEL
        INIT_TEXT_SECTION(PAGE_SIZE)
-       . = ALIGN(16);
-       INIT_DATA_SECTION(16)
-       PERCPU(4)
 
-       /* we have to discard exit text and such at runtime, not link time, to
+       /* We have to discard exit text and such at runtime, not link time, to
         * handle embedded cross-section references (alt instructions, bug
-        * table, eh_frame, etc...)
+        * table, eh_frame, etc...).  We need all of our .text up front and
+        * .data after it for PCREL call issues.
         */
        .exit.text :
        {
                EXIT_TEXT
        }
+
+       . = ALIGN(16);
+       INIT_DATA_SECTION(16)
+       PERCPU(4)
+
        .exit.data :
        {
                EXIT_DATA
        }
 
        .text_l1 L1_CODE_START : AT(LOADADDR(.exit.data) + SIZEOF(.exit.data))
+#else
+       .init.data : AT(__data_lma + __data_len)
+       {
+               __sinitdata = .;
+               INIT_DATA
+               INIT_SETUP(16)
+               INIT_CALLS
+               CON_INITCALL
+               SECURITY_INITCALL
+               INIT_RAM_FS
+
+               . = ALIGN(4);
+               ___per_cpu_load = .;
+               ___per_cpu_start = .;
+               *(.data.percpu.first)
+               *(.data.percpu.page_aligned)
+               *(.data.percpu)
+               *(.data.percpu.shared_aligned)
+               ___per_cpu_end = .;
+
+               EXIT_DATA
+               __einitdata = .;
+       }
+       __init_data_lma = LOADADDR(.init.data);
+       __init_data_len = SIZEOF(.init.data);
+       __init_data_end = .;
+
+       .text_l1 L1_CODE_START : AT(__init_data_lma + __init_data_len)
+#endif
        {
                . = ALIGN(4);
                __stext_l1 = .;
@@ -202,7 +258,11 @@ SECTIONS
        /* Force trailing alignment of our init section so that when we
         * free our init memory, we don't leave behind a partial page.
         */
+#ifdef CONFIG_RAMKERNEL
        . = __l2_lma + __l2_len;
+#else
+       . = __init_data_end;
+#endif
        . = ALIGN(PAGE_SIZE);
        ___init_end = .;
 
index 9616351..252261e 100644 (file)
@@ -9,4 +9,9 @@ config BFIN518F_EZBRD
        help
          BF518-EZBRD board support.
 
+config BFIN518F_TCM
+       bool "Bluetechnix TCM-BF518"
+       help
+         Bluetechnix TCM-BF518 board support.
+
 endchoice
index 172e859..a9ef25c 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_BFIN518F_EZBRD)            += ezbrd.o
+obj-$(CONFIG_BFIN518F_TCM)             += tcm-bf518.o
index 01975c0..44d6d52 100644 (file)
@@ -382,30 +382,93 @@ static struct platform_device bfin_spi1_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
-#endif
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -499,16 +562,75 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
@@ -593,7 +715,12 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -610,9 +737,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -644,6 +775,33 @@ static int __init ezbrd_init(void)
 
 arch_initcall(ezbrd_init);
 
+static struct platform_device *ezbrd_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezbrd_early_devices,
+               ARRAY_SIZE(ezbrd_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
diff --git a/arch/blackfin/mach-bf518/boards/tcm-bf518.c b/arch/blackfin/mach-bf518/boards/tcm-bf518.c
new file mode 100644 (file)
index 0000000..9b72e5c
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *                2005 National ICT Australia (NICTA)
+ *                      Aidan Williams <aidan@nicta.com.au>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+#include <asm/bfin_sdh.h>
+#include <linux/spi/ad7877.h>
+#include <net/dsa.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "Bluetechnix TCM-BF518";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition tcm_partitions[] = {
+       {
+               .name       = "bootloader(nor)",
+               .size       = 0x40000,
+               .offset     = 0,
+       },
+       {
+               .name       = "linux(nor)",
+               .size       = 0x1C0000,
+               .offset     = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct physmap_flash_data tcm_flash_data = {
+       .width      = 2,
+       .parts      = tcm_partitions,
+       .nr_parts   = ARRAY_SIZE(tcm_partitions),
+};
+
+static struct resource tcm_flash_resource = {
+       .start = 0x20000000,
+       .end   = 0x201fffff,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device tcm_flash_device = {
+       .name          = "physmap-flash",
+       .id            = 0,
+       .dev = {
+               .platform_data = &tcm_flash_data,
+       },
+       .num_resources = 1,
+       .resource      = &tcm_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+       .name = "rtc-bfin",
+       .id   = -1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mii_bus = {
+       .name = "bfin_mii_bus",
+};
+
+static struct platform_device bfin_mac_device = {
+       .name = "bfin_mac",
+       .dev.platform_data = &bfin_mii_bus,
+};
+#endif
+
+#if defined(CONFIG_MTD_M25P80) \
+       || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+       {
+               .name = "bootloader(spi)",
+               .size = 0x00040000,
+               .offset = 0,
+               .mask_flags = MTD_CAP_ROM
+       }, {
+               .name = "linux kernel(spi)",
+               .size = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+       .name = "m25p80",
+       .parts = bfin_spi_flash_partitions,
+       .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+       .type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+       .enable_dma = 0,         /* use dma transfer with this chip*/
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+       .enable_dma = 1,         /* use dma transfer with this chip*/
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+static struct bfin5xx_spi_chip mmc_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+       .model                  = 7877,
+       .vref_delay_usecs       = 50,   /* internal, no capacitor */
+       .x_plate_ohms           = 419,
+       .y_plate_ohms           = 486,
+       .pressure_max           = 1000,
+       .pressure_min           = 0,
+       .stopacq_polarity       = 1,
+       .first_conversion_delay = 3,
+       .acquisition_time       = 1,
+       .averaging              = 1,
+       .pen_down_acc_interval  = 1,
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+        && defined(CONFIG_SND_SOC_WM8731_SPI)
+static struct bfin5xx_spi_chip spi_wm8731_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+       || defined(CONFIG_MTD_M25P80_MODULE)
+       {
+               /* the modalias must be the same as spi device driver name */
+               .modalias = "m25p80", /* Name of spi_driver for this device */
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0, /* Framework bus number */
+               .chip_select = 2, /* SPI0_SSEL2 */
+               .platform_data = &bfin_spi_flash_data,
+               .controller_data = &spi_flash_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
+       {
+               .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+               .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0, /* Framework bus number */
+               .chip_select = 1, /* Framework chip select. */
+               .platform_data = NULL, /* No spi_driver specific config */
+               .controller_data = &spi_adc_chip_info,
+       },
+#endif
+
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+       {
+               .modalias = "mmc_spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 5,
+               .controller_data = &mmc_spi_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+       {
+               .modalias               = "ad7877",
+               .platform_data          = &bfin_ad7877_ts_info,
+               .irq                    = IRQ_PF8,
+               .max_speed_hz   = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num        = 0,
+               .chip_select  = 2,
+               .controller_data = &spi_ad7877_chip_info,
+       },
+#endif
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+        && defined(CONFIG_SND_SOC_WM8731_SPI)
+       {
+               .modalias       = "wm8731",
+               .max_speed_hz   = 3125000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num        = 0,
+               .chip_select    = 5,
+               .controller_data = &spi_wm8731_chip_info,
+               .mode = SPI_MODE_0,
+       },
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+       {
+               .modalias = "spidev",
+               .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &spidev_chip_info,
+       },
+#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       {
+               .modalias = "bfin-lq035q1-spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &lq035q1_spi_chip_info,
+               .mode = SPI_CPHA | SPI_CPOL,
+       },
+#endif
+};
+
+/* SPI controller data */
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI (0) */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+       .num_chipselect = 6,
+       .enable_dma = 1,  /* master has the ability to do dma transfer */
+       .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+static struct resource bfin_spi0_resource[] = {
+       [0] = {
+               .start = SPI0_REGBASE,
+               .end   = SPI0_REGBASE + 0xFF,
+               .flags = IORESOURCE_MEM,
+               },
+       [1] = {
+               .start = CH_SPI0,
+               .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_spi0_device = {
+       .name = "bfin-spi",
+       .id = 0, /* Bus number */
+       .num_resources = ARRAY_SIZE(bfin_spi0_resource),
+       .resource = bfin_spi0_resource,
+       .dev = {
+               .platform_data = &bfin_spi0_info, /* Passed to driver */
+       },
+};
+
+/* SPI (1) */
+static struct bfin5xx_spi_master bfin_spi1_info = {
+       .num_chipselect = 5,
+       .enable_dma = 1,  /* master has the ability to do dma transfer */
+       .pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
+};
+
+static struct resource bfin_spi1_resource[] = {
+       [0] = {
+               .start = SPI1_REGBASE,
+               .end   = SPI1_REGBASE + 0xFF,
+               .flags = IORESOURCE_MEM,
+               },
+       [1] = {
+               .start = CH_SPI1,
+               .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_spi1_device = {
+       .name = "bfin-spi",
+       .id = 1, /* Bus number */
+       .num_resources = ARRAY_SIZE(bfin_spi1_resource),
+       .resource = bfin_spi1_resource,
+       .dev = {
+               .platform_data = &bfin_spi1_info, /* Passed to driver */
+       },
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
+       {
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+       {
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+static struct resource bfin_sir0_resources[] = {
+       {
+               .start = 0xFFC00400,
+               .end = 0xFFC004FF,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX+1,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device bfin_sir0_device = {
+       .name = "bfin_sir",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sir0_resources),
+       .resource = bfin_sir0_resources,
+};
+#endif
+#ifdef CONFIG_BFIN_SIR1
+static struct resource bfin_sir1_resources[] = {
+       {
+               .start = 0xFFC02000,
+               .end = 0xFFC020FF,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX+1,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device bfin_sir1_device = {
+       .name = "bfin_sir",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sir1_resources),
+       .resource = bfin_sir1_resources,
+};
+#endif
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+       [0] = {
+               .start = TWI0_REGBASE,
+               .end   = TWI0_REGBASE,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TWI,
+               .end   = IRQ_TWI,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+       .name = "i2c-bfin-twi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_twi0_resource),
+       .resource = bfin_twi0_resource,
+};
+#endif
+
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+       {
+               I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+       },
+#endif
+#if defined(CONFIG_INPUT_PCF8574) || defined(CONFIG_INPUT_PCF8574_MODULE)
+       {
+               I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+               .irq = IRQ_PF8,
+       },
+#endif
+};
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+       {BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
+       {BTN_1, GPIO_PG13, 1, "gpio-keys: BTN1"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+       .buttons        = bfin_gpio_keys_table,
+       .nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+       .name      = "gpio-keys",
+       .dev = {
+               .platform_data = &bfin_gpio_keys_data,
+       },
+};
+#endif
+
+#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN_MODULE)
+
+static struct bfin_sd_host bfin_sdh_data = {
+       .dma_chan = CH_RSI,
+       .irq_int0 = IRQ_RSI_INT0,
+       .pin_req = {P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3, P_RSI_CMD, P_RSI_CLK, 0},
+};
+
+static struct platform_device bf51x_sdh_device = {
+       .name = "bfin-sdh",
+       .id = 0,
+       .dev = {
+               .platform_data = &bfin_sdh_data,
+       },
+};
+#endif
+
+static const unsigned int cclk_vlev_datasheet[] =
+{
+       VRPAIR(VLEV_100, 400000000),
+       VRPAIR(VLEV_105, 426000000),
+       VRPAIR(VLEV_110, 500000000),
+       VRPAIR(VLEV_115, 533000000),
+       VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+       .tuple_tab = cclk_vlev_datasheet,
+       .tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+       .vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+       .name = "bfin dpmc",
+       .dev = {
+               .platform_data = &bfin_dmpc_vreg_data,
+       },
+};
+
+static struct platform_device *tcm_devices[] __initdata = {
+
+       &bfin_dpmc,
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+       &rtc_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       &bfin_mii_bus,
+       &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+       &bfin_spi0_device,
+       &bfin_spi1_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+       &bfin_sir0_device,
+#endif
+#ifdef CONFIG_BFIN_SIR1
+       &bfin_sir1_device,
+#endif
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+       &i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+       &bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN_MODULE)
+       &bf51x_sdh_device,
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+       &tcm_flash_device,
+#endif
+};
+
+static int __init tcm_init(void)
+{
+       printk(KERN_INFO "%s(): registering device resources\n", __func__);
+       i2c_register_board_info(0, bfin_i2c_board_info,
+                               ARRAY_SIZE(bfin_i2c_board_info));
+       platform_add_devices(tcm_devices, ARRAY_SIZE(tcm_devices));
+       spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+       return 0;
+}
+
+arch_initcall(tcm_init);
+
+static struct platform_device *tcm_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(tcm_early_devices,
+               ARRAY_SIZE(tcm_early_devices));
+}
+
+void native_machine_restart(char *cmd)
+{
+       /* workaround reboot hang when booting from SPI */
+       if ((bfin_read_SYSCR() & 0x7) == 0x3)
+               bfin_reset_boot_spi_cs(P_DEFAULT_BOOT_SPI_CS);
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+       random_ether_addr(addr);
+       printk(KERN_WARNING "%s:%s: Setting Ethernet MAC to a random one\n", __FILE__, __func__);
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
index 14e52ec..435e76e 100644 (file)
 
 #define GPIO_IRQ_BASE  IRQ_PF0
 
-#define NR_IRQS     (IRQ_PH15 + 1)
+#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
+#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7            7
 #define IVG8            8
index 3c6777c..073b5d7 100644 (file)
@@ -41,7 +41,7 @@
 #define L1_DATA_A_START                0xFF800000
 #define L1_DATA_B_START                0xFF900000
 
-#define L1_CODE_LENGTH         0xC000
+#define L1_CODE_LENGTH         0x8000
 
 #ifdef CONFIG_BFIN_DCACHE
 
index df224d0..b14c288 100644 (file)
@@ -9,6 +9,11 @@ config BFIN527_EZKIT
        help
          BF527-EZKIT-LITE board support.
 
+config BFIN527_EZKIT_V2
+       bool "BF527-EZKIT-V2"
+       help
+         BF527-EZKIT-LITE V2.1+ board support.
+
 config BFIN527_BLUETECHNIX_CM
        bool "Bluetechnix CM-BF527"
        help
index eb6ed33..51a5817 100644 (file)
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_BFIN527_EZKIT)            += ezkit.o
+obj-$(CONFIG_BFIN527_EZKIT_V2)         += ezkit.o
 obj-$(CONFIG_BFIN527_BLUETECHNIX_CM)   += cm_bf527.o
 obj-$(CONFIG_BFIN526_EZBRD)            += ezbrd.o
index 7ab0800..ebe76d1 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/i2c.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb/sl811.h>
 #include <linux/usb/musb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
@@ -270,50 +269,6 @@ static struct platform_device dm9000_device = {
 };
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-static struct resource sl811_hcd_resources[] = {
-       {
-               .start = 0x20340000,
-               .end = 0x20340000,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0x20340004,
-               .end = 0x20340004,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = CONFIG_USB_SL811_BFIN_IRQ,
-               .end = CONFIG_USB_SL811_BFIN_IRQ,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       },
-};
-
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-void sl811_port_power(struct device *dev, int is_on)
-{
-       gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-       gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
-}
-#endif
-
-static struct sl811_platform_data sl811_priv = {
-       .potpg = 10,
-       .power = 250,       /* == 500mA */
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-       .port_power = &sl811_port_power,
-#endif
-};
-
-static struct platform_device sl811_hcd_device = {
-       .name = "sl811-hcd",
-       .id = 0,
-       .dev = {
-               .platform_data = &sl811_priv,
-       },
-       .num_resources = ARRAY_SIZE(sl811_hcd_resources),
-       .resource = sl811_hcd_resources,
-};
-#endif
-
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
@@ -384,8 +339,8 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -462,8 +417,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -603,30 +558,105 @@ static struct platform_device cm_flash_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       {       /* CTS pin */
+               .start = GPIO_PF9,
+               .end = GPIO_PF9,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin */
+               .start = GPIO_PF10,
+               .end = GPIO_PF10,
+               .flags = IORESOURCE_IO,
+       },
 #endif
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -725,16 +755,75 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
@@ -795,10 +884,6 @@ static struct platform_device *cmbf527_devices[] __initdata = {
        &rtc_device,
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-       &sl811_hcd_device,
-#endif
-
 #if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
        &bfin_isp1760_device,
 #endif
@@ -829,7 +914,12 @@ static struct platform_device *cmbf527_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -846,9 +936,13 @@ static struct platform_device *cmbf527_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -871,6 +965,33 @@ static int __init cm_init(void)
 
 arch_initcall(cm_init);
 
+static struct platform_device *cmbf527_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cmbf527_early_devices,
+               ARRAY_SIZE(cmbf527_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
index cad23b1..55069af 100644 (file)
@@ -274,8 +274,8 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
        .median                 = 2,    /* do 8 measurements */
        .averaging              = 1,    /* take the average of 4 middle samples */
        .pen_down_acc_interval  = 255,  /* 9.4 ms */
-       .gpio_output            = 1,    /* configure AUX/VBAT/GPIO as GPIO output */
-       .gpio_default           = 1,    /* During initialization set GPIO = HIGH */
+       .gpio_export            = 1,    /* Export GPIO to gpiolib */
+       .gpio_base              = -1,   /* Dynamic allocation */
 };
 #endif
 
@@ -439,30 +439,105 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       {       /* CTS pin */
+               .start = GPIO_PG0,
+               .end = GPIO_PG0,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin */
+               .start = GPIO_PF10,
+               .end = GPIO_PF10,
+               .flags = IORESOURCE_IO,
+       },
 #endif
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -556,16 +631,75 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
@@ -615,9 +749,10 @@ static struct platform_device bfin_dpmc = {
 #include <asm/bfin-lq035q1.h>
 
 static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
-       .mode =         LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
-       .use_bl =       1,
-       .gpio_bl =      GPIO_PG12,
+       .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .ppi_mode = USE_RGB565_16_BIT_PPI,
+       .use_bl = 1,
+       .gpio_bl = GPIO_PG12,
 };
 
 static struct resource bfin_lq035q1_resources[] = {
@@ -665,7 +800,12 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
@@ -686,9 +826,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -711,6 +855,33 @@ static int __init ezbrd_init(void)
 
 arch_initcall(ezbrd_init);
 
+static struct platform_device *ezbrd_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezbrd_early_devices,
+               ARRAY_SIZE(ezbrd_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
index 5294fdd..9233833 100644 (file)
@@ -16,8 +16,9 @@
 #include <linux/i2c.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb/sl811.h>
 #include <linux/usb/musb.h>
+#include <linux/leds.h>
+#include <linux/input.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
 /*
  * Name the Board for the /proc/cpuinfo
  */
+#ifdef CONFIG_BFIN527_EZKIT_V2
+const char bfin_board_name[] = "ADI BF527-EZKIT V2";
+#else
 const char bfin_board_name[] = "ADI BF527-EZKIT";
+#endif
 
 /*
  *  Driver needs to know address, irq and flag pin.
@@ -143,6 +148,33 @@ static struct platform_device bf52x_t350mcqb_device = {
 };
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+       .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .ppi_mode = USE_RGB565_8_BIT_PPI,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+       {
+               .start = IRQ_PPI_ERROR,
+               .end = IRQ_PPI_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_lq035q1_device = {
+       .name           = "bfin-lq035q1",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(bfin_lq035q1_resources),
+       .resource       = bfin_lq035q1_resources,
+       .dev            = {
+               .platform_data = &bfin_lq035q1_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 static struct mtd_partition ezkit_partitions[] = {
        {
@@ -326,50 +358,6 @@ static struct platform_device dm9000_device = {
 };
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-static struct resource sl811_hcd_resources[] = {
-       {
-               .start = 0x20340000,
-               .end = 0x20340000,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0x20340004,
-               .end = 0x20340004,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = CONFIG_USB_SL811_BFIN_IRQ,
-               .end = CONFIG_USB_SL811_BFIN_IRQ,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       },
-};
-
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-void sl811_port_power(struct device *dev, int is_on)
-{
-       gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-       gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
-}
-#endif
-
-static struct sl811_platform_data sl811_priv = {
-       .potpg = 10,
-       .power = 250,       /* == 500mA */
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-       .port_power = &sl811_port_power,
-#endif
-};
-
-static struct platform_device sl811_hcd_device = {
-       .name = "sl811-hcd",
-       .id = 0,
-       .dev = {
-               .platform_data = &sl811_priv,
-       },
-       .num_resources = ARRAY_SIZE(sl811_hcd_resources),
-       .resource = sl811_hcd_resources,
-};
-#endif
-
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
@@ -440,8 +428,8 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -488,8 +476,7 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
        .median                 = 2,    /* do 8 measurements */
        .averaging              = 1,    /* take the average of 4 middle samples */
        .pen_down_acc_interval  = 255,  /* 9.4 ms */
-       .gpio_output            = 1,    /* configure AUX/VBAT/GPIO as GPIO output */
-       .gpio_default           = 1,    /* During initialization set GPIO = HIGH */
+       .gpio_export            = 0,    /* Export GPIO to gpiolib */
 };
 #endif
 
@@ -500,14 +487,6 @@ static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
-        && defined(CONFIG_SND_SOC_WM8731_SPI)
-static struct bfin5xx_spi_chip spi_wm8731_chip_info = {
-       .enable_dma = 0,
-       .bits_per_word = 16,
-};
-#endif
-
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 static struct bfin5xx_spi_chip spidev_chip_info = {
        .enable_dma = 0,
@@ -515,6 +494,29 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+       .name = "bfin-i2s",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+       .name = "bfin-tdm",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+       .enable_dma     = 0,
+       .bits_per_word  = 8,
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -542,8 +544,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -586,17 +588,6 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .mode = SPI_CPHA | SPI_CPOL,
        },
 #endif
-#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
-        && defined(CONFIG_SND_SOC_WM8731_SPI)
-       {
-               .modalias       = "wm8731",
-               .max_speed_hz   = 3125000,     /* max spi clock (SCK) speed in HZ */
-               .bus_num        = 0,
-               .chip_select    = 5,
-               .controller_data = &spi_wm8731_chip_info,
-               .mode = SPI_MODE_0,
-       },
-#endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
        {
                .modalias = "spidev",
@@ -606,6 +597,16 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .controller_data = &spidev_chip_info,
        },
 #endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       {
+               .modalias = "bfin-lq035q1-spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 7,
+               .controller_data = &lq035q1_spi_chip_info,
+               .mode = SPI_CPHA | SPI_CPOL,
+       },
+#endif
 };
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -647,30 +648,105 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       {       /* CTS pin */
+               .start = GPIO_PF9,
+               .end = GPIO_PF9,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin */
+               .start = GPIO_PF10,
+               .end = GPIO_PF10,
+               .flags = IORESOURCE_IO,
+       },
 #endif
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -749,6 +825,71 @@ static struct platform_device i2c_bfin_twi_device = {
 };
 #endif
 
+#if defined(CONFIG_PMIC_ADP5520) || defined(CONFIG_PMIC_ADP5520_MODULE)
+#include <linux/mfd/adp5520.h>
+
+       /*
+        *  ADP5520/5501 LEDs Data
+        */
+
+static struct led_info adp5520_leds[] = {
+       {
+               .name = "adp5520-led1",
+               .default_trigger = "none",
+               .flags = FLAG_ID_ADP5520_LED1_ADP5501_LED0 | ADP5520_LED_OFFT_600ms,
+       },
+};
+
+static struct adp5520_leds_platform_data adp5520_leds_data = {
+       .num_leds = ARRAY_SIZE(adp5520_leds),
+       .leds = adp5520_leds,
+       .fade_in = ADP5520_FADE_T_600ms,
+       .fade_out = ADP5520_FADE_T_600ms,
+       .led_on_time = ADP5520_LED_ONT_600ms,
+};
+
+       /*
+        *  ADP5520 Keypad Data
+        */
+
+static const unsigned short adp5520_keymap[ADP5520_KEYMAPSIZE] = {
+       [ADP5520_KEY(3, 3)]     = KEY_1,
+       [ADP5520_KEY(2, 3)]     = KEY_2,
+       [ADP5520_KEY(1, 3)]     = KEY_3,
+       [ADP5520_KEY(0, 3)]     = KEY_UP,
+       [ADP5520_KEY(3, 2)]     = KEY_4,
+       [ADP5520_KEY(2, 2)]     = KEY_5,
+       [ADP5520_KEY(1, 2)]     = KEY_6,
+       [ADP5520_KEY(0, 2)]     = KEY_DOWN,
+       [ADP5520_KEY(3, 1)]     = KEY_7,
+       [ADP5520_KEY(2, 1)]     = KEY_8,
+       [ADP5520_KEY(1, 1)]     = KEY_9,
+       [ADP5520_KEY(0, 1)]     = KEY_DOT,
+       [ADP5520_KEY(3, 0)]     = KEY_BACKSPACE,
+       [ADP5520_KEY(2, 0)]     = KEY_0,
+       [ADP5520_KEY(1, 0)]     = KEY_HELP,
+       [ADP5520_KEY(0, 0)]     = KEY_ENTER,
+};
+
+static struct adp5520_keys_platform_data adp5520_keys_data = {
+       .rows_en_mask   = ADP5520_ROW_R3 | ADP5520_ROW_R2 | ADP5520_ROW_R1 | ADP5520_ROW_R0,
+       .cols_en_mask   = ADP5520_COL_C3 | ADP5520_COL_C2 | ADP5520_COL_C1 | ADP5520_COL_C0,
+       .keymap         = adp5520_keymap,
+       .keymapsize     = ARRAY_SIZE(adp5520_keymap),
+       .repeat         = 0,
+};
+
+       /*
+        *  ADP5520/5501 Multifuction Device Init Data
+        */
+
+static struct adp5520_platform_data adp5520_pdev_data = {
+       .leds = &adp5520_leds_data,
+       .keys = &adp5520_keys_data,
+};
+
+#endif
+
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
@@ -766,22 +907,99 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                I2C_BOARD_INFO("bfin-adv7393", 0x2B),
        },
 #endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
+       {
+               I2C_BOARD_INFO("ad7879", 0x2C),
+               .irq = IRQ_PF8,
+               .platform_data = (void *)&bfin_ad7879_ts_info,
+       },
+#endif
+#if defined(CONFIG_PMIC_ADP5520) || defined(CONFIG_PMIC_ADP5520_MODULE)
+       {
+               I2C_BOARD_INFO("pmic-adp5520", 0x32),
+               .irq = IRQ_PF9,
+               .platform_data = (void *)&adp5520_pdev_data,
+       },
+#endif
+#if defined(CONFIG_SND_SOC_SSM2602) || defined(CONFIG_SND_SOC_SSM2602_MODULE)
+       {
+               I2C_BOARD_INFO("ssm2602", 0x1b),
+       },
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-#include <linux/input.h>
 #include <linux/gpio_keys.h>
 
 static struct gpio_keys_button bfin_gpio_keys_table[] = {
@@ -803,7 +1021,6 @@ static struct platform_device bfin_device_gpiokeys = {
 #endif
 
 #if defined(CONFIG_INPUT_BFIN_ROTARY) || defined(CONFIG_INPUT_BFIN_ROTARY_MODULE)
-#include <linux/input.h>
 #include <asm/bfin_rotary.h>
 
 static struct bfin_rotary_platform_data bfin_rotary_data = {
@@ -872,10 +1089,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &rtc_device,
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-       &sl811_hcd_device,
-#endif
-
 #if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
        &bfin_isp1760_device,
 #endif
@@ -909,8 +1122,17 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bf52x_t350mcqb_device,
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       &bfin_lq035q1_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -927,9 +1149,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -942,6 +1168,14 @@ static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
        &ezkit_flash_device,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_tdm,
+#endif
 };
 
 static int __init ezkit_init(void)
@@ -956,6 +1190,33 @@ static int __init ezkit_init(void)
 
 arch_initcall(ezkit_init);
 
+static struct platform_device *ezkit_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezkit_early_devices,
+               ARRAY_SIZE(ezkit_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
index aa6579a..704d925 100644 (file)
 
 #define GPIO_IRQ_BASE  IRQ_PF0
 
-#define NR_IRQS     (IRQ_PH15+1)
+#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
+#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7            7
 #define IVG8            8
index 4adceb0..175371a 100644 (file)
@@ -171,7 +171,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -206,7 +206,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 16,
@@ -257,21 +257,50 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -394,7 +423,9 @@ static struct platform_device *h8606_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
@@ -424,3 +455,18 @@ static int __init H8606_init(void)
 }
 
 arch_initcall(H8606_init);
+
+static struct platform_device *H8606_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(H8606_early_devices,
+               ARRAY_SIZE(H8606_early_devices));
+}
index b580884..842b4fa 100644 (file)
@@ -195,21 +195,50 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -241,16 +270,75 @@ static struct platform_device bfin_sir0_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
@@ -344,7 +432,9 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -354,9 +444,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -392,3 +486,27 @@ static int __init blackstamp_init(void)
 }
 
 arch_initcall(blackstamp_init);
+
+static struct platform_device *stamp_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(stamp_early_devices,
+               ARRAY_SIZE(stamp_early_devices));
+}
index 7fc3b86..fdcde61 100644 (file)
@@ -71,7 +71,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -110,7 +110,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -242,21 +242,50 @@ static struct platform_device smsc911x_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -288,16 +317,75 @@ static struct platform_device bfin_sir0_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 static struct resource isp1362_hcd_resources[] = {
@@ -432,7 +520,9 @@ static struct platform_device *cm_bf533_devices[] __initdata = {
        &bfin_dpmc,
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -442,9 +532,13 @@ static struct platform_device *cm_bf533_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
        &rtc_device,
@@ -486,3 +580,27 @@ static int __init cm_bf533_init(void)
 }
 
 arch_initcall(cm_bf533_init);
+
+static struct platform_device *cm_bf533_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf533_early_devices,
+               ARRAY_SIZE(cm_bf533_early_devices));
+}
index d4689dc..739773c 100644 (file)
@@ -222,7 +222,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -261,7 +261,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -320,21 +320,50 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -444,6 +473,30 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #endif
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+       .name = "bfin-i2s",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+       .name = "bfin-tdm",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97 = {
+       .name = "bfin-ac97",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 
        &bfin_dpmc,
@@ -471,7 +524,9 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -487,6 +542,18 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
        &i2c_gpio_device,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_tdm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_ac97,
+#endif
 };
 
 static int __init ezkit_init(void)
@@ -500,3 +567,18 @@ static int __init ezkit_init(void)
 }
 
 arch_initcall(ezkit_init);
+
+static struct platform_device *ezkit_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezkit_early_devices,
+               ARRAY_SIZE(ezkit_early_devices));
+}
index 8ec42ba..7349970 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/usb/isp1362.h>
 #endif
 #include <asm/irq.h>
+#include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
 
@@ -143,21 +144,50 @@ static struct platform_device spi_bfin_master_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -241,7 +271,9 @@ static struct platform_device *ip0x_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -276,3 +308,18 @@ static int __init ip0x_init(void)
 }
 
 arch_initcall(ip0x_init);
+
+static struct platform_device *ip0x_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ip0x_early_devices,
+               ARRAY_SIZE(ip0x_early_devices));
+}
index 6d68dcf..c457eaa 100644 (file)
@@ -184,7 +184,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -251,7 +251,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -322,21 +322,50 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX + 1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -368,16 +397,75 @@ static struct platform_device bfin_sir0_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
@@ -474,6 +562,30 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+       .name = "bfin-i2s",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+       .name = "bfin-tdm",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97 = {
+       .name = "bfin-ac97",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
 static struct platform_device *stamp_devices[] __initdata = {
 
        &bfin_dpmc,
@@ -495,7 +607,9 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -505,9 +619,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
        &bfin_device_gpiokeys,
@@ -520,6 +638,18 @@ static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_MTD_BFIN_ASYNC) || defined(CONFIG_MTD_BFIN_ASYNC_MODULE)
        &stamp_flash_device,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_tdm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_ac97,
+#endif
 };
 
 static int __init stamp_init(void)
@@ -548,6 +678,30 @@ static int __init stamp_init(void)
 
 arch_initcall(stamp_init);
 
+static struct platform_device *stamp_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(stamp_early_devices,
+               ARRAY_SIZE(stamp_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround pull up on cpld / flash pin not being strong enough */
index c31498b..1f7e976 100644 (file)
@@ -104,7 +104,8 @@ Core        Emulation               **
 
 #define GPIO_IRQ_BASE          IRQ_PF0
 
-#define        NR_IRQS         (IRQ_PF15+1)
+#define NR_MACH_IRQS           (IRQ_PF15 + 1)
+#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7                   7
 #define IVG8                   8
index c85f4d7..d35fc5f 100644 (file)
@@ -73,7 +73,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -112,7 +112,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -329,8 +329,8 @@ static struct platform_device cm_flash_device = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
 static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
        {
@@ -373,18 +373,25 @@ static struct resource bfin_uart0_resources[] = {
 #endif
 };
 
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
 static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
        .id = 0,
        .num_resources = ARRAY_SIZE(bfin_uart0_resources),
        .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
 static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
        {
@@ -427,11 +434,18 @@ static struct resource bfin_uart1_resources[] = {
 #endif
 };
 
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
 static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
        .num_resources = ARRAY_SIZE(bfin_uart1_resources),
        .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
 #endif
@@ -512,16 +526,75 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
@@ -633,9 +706,13 @@ static struct platform_device *cm_bf537e_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
        &isp1362_hcd_device,
@@ -683,6 +760,33 @@ static int __init cm_bf537e_init(void)
 
 arch_initcall(cm_bf537e_init);
 
+static struct platform_device *cm_bf537e_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf537e_early_devices,
+               ARRAY_SIZE(cm_bf537e_early_devices));
+}
+
 void bfin_get_ether_addr(char *addr)
 {
        random_ether_addr(addr);
index ea11aa8..d464ad5 100644 (file)
@@ -74,7 +74,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -113,7 +113,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -327,25 +327,93 @@ static struct platform_device cm_flash_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+       {
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -423,16 +491,75 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
@@ -522,7 +649,12 @@ static struct platform_device *cm_bf537u_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -539,9 +671,13 @@ static struct platform_device *cm_bf537u_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
        &isp1362_hcd_device,
@@ -589,6 +725,33 @@ static int __init cm_bf537u_init(void)
 
 arch_initcall(cm_bf537u_init);
 
+static struct platform_device *cm_bf537u_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf537u_early_devices,
+               ARRAY_SIZE(cm_bf537u_early_devices));
+}
+
 void bfin_get_ether_addr(char *addr)
 {
        random_ether_addr(addr);
index 0da9272..c489d60 100644 (file)
@@ -211,25 +211,93 @@ static struct platform_device bfin_spi0_device = {
 #endif  /* spi master and devices */
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+       {
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -309,16 +377,75 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 static struct platform_device *minotaur_devices[] __initdata = {
 #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
@@ -343,7 +470,12 @@ static struct platform_device *minotaur_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -360,9 +492,13 @@ static struct platform_device *minotaur_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 };
 
@@ -380,6 +516,33 @@ static int __init minotaur_init(void)
 
 arch_initcall(minotaur_init);
 
+static struct platform_device *minotaur_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(minotaur_early_devices,
+               ARRAY_SIZE(minotaur_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
index 4e0afda..812e8f9 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
-#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 
@@ -99,51 +98,6 @@ static struct platform_device smc91x_device = {
 };
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-static struct resource sl811_hcd_resources[] = {
-       {
-               .start = 0x20340000,
-               .end = 0x20340000,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0x20340004,
-               .end = 0x20340004,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = CONFIG_USB_SL811_BFIN_IRQ,
-               .end = CONFIG_USB_SL811_BFIN_IRQ,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       },
-};
-
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-void sl811_port_power(struct device *dev, int is_on)
-{
-       gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-       gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
-
-}
-#endif
-
-static struct sl811_platform_data sl811_priv = {
-       .potpg = 10,
-       .power = 250,       /* == 500mA */
-#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
-       .port_power = &sl811_port_power,
-#endif
-};
-
-static struct platform_device sl811_hcd_device = {
-       .name = "sl811-hcd",
-       .id = 0,
-       .dev = {
-               .platform_data = &sl811_priv,
-       },
-       .num_resources = ARRAY_SIZE(sl811_hcd_resources),
-       .resource = sl811_hcd_resources,
-};
-#endif
-
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
        .name = "bfin_mii_bus",
@@ -221,8 +175,8 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -284,8 +238,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -362,25 +316,93 @@ static struct platform_device bfin_fb_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+       {
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -446,10 +468,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &rtc_device,
 #endif
 
-#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
-       &sl811_hcd_device,
-#endif
-
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
        &smc91x_device,
 #endif
@@ -472,7 +490,12 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -498,6 +521,24 @@ static int __init pnav_init(void)
 
 arch_initcall(pnav_init);
 
+static struct platform_device *stamp_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(stamp_early_devices,
+               ARRAY_SIZE(stamp_early_devices));
+}
+
 void bfin_get_ether_addr(char *addr)
 {
        random_ether_addr(addr);
index ac9b52e..9eaf5b0 100644 (file)
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
+#include <linux/i2c.h>
+#include <linux/i2c/adp5588.h>
+#include <linux/etherdevice.h>
 #include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/i2c.h>
 #include <linux/usb/sl811.h>
 #include <linux/spi/mmc_spi.h>
 #include <linux/leds.h>
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#ifdef CONFIG_REGULATOR_ADP_SWITCH
+#include <linux/regulator/adp_switch.h>
+#endif
+#ifdef CONFIG_REGULATOR_AD5398
+#include <linux/regulator/ad5398.h>
+#endif
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/userspace-consumer.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -208,8 +218,8 @@ static struct resource sl811_hcd_resources[] = {
                .end = 0x20340004,
                .flags = IORESOURCE_MEM,
        }, {
-               .start = CONFIG_USB_SL811_BFIN_IRQ,
-               .end = CONFIG_USB_SL811_BFIN_IRQ,
+               .start = IRQ_PF4,
+               .end = IRQ_PF4,
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
@@ -454,6 +464,9 @@ static struct physmap_flash_data stamp_flash_data = {
        .width      = 2,
        .parts      = stamp_partitions,
        .nr_parts   = ARRAY_SIZE(stamp_partitions),
+#ifdef CONFIG_ROMKERNEL
+       .probe_type = "map_rom",
+#endif
 };
 
 static struct resource stamp_flash_resource = {
@@ -515,20 +528,19 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
-       || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+       || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD1938) \
-       || defined(CONFIG_SND_BF5XX_SOC_AD1938_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD193X) \
+       || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE)
 static struct bfin5xx_spi_chip ad1938_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 8,
-       .cs_gpio = GPIO_PF5,
 };
 #endif
 
@@ -644,6 +656,42 @@ static struct ad714x_platform_data ad7142_i2c_platform_data = {
 };
 #endif
 
+#if defined(CONFIG_AD2S90) || defined(CONFIG_AD2S90_MODULE)
+static struct bfin5xx_spi_chip ad2s90_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD2S120X) || defined(CONFIG_AD2S120X_MODULE)
+unsigned short ad2s120x_platform_data[] = {
+       /* used as SAMPLE and RDVEL */
+       GPIO_PF5, GPIO_PF6, 0
+};
+
+static struct bfin5xx_spi_chip ad2s120x_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD2S1210) || defined(CONFIG_AD2S1210_MODULE)
+unsigned short ad2s1210_platform_data[] = {
+       /* use as SAMPLE, A0, A1 */
+       GPIO_PF7, GPIO_PF8, GPIO_PF9,
+# if defined(CONFIG_AD2S1210_GPIO_INPUT) || defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+       /* the RES0 and RES1 pins */
+       GPIO_PF4, GPIO_PF5,
+# endif
+       0,
+};
+
+static struct bfin5xx_spi_chip ad2s1210_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
 #define MMC_SPI_CARD_DETECT_INT IRQ_PF5
 
@@ -686,11 +734,11 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
        .y_plate_ohms           = 486,
        .pressure_max           = 1000,
        .pressure_min           = 0,
-       .stopacq_polarity       = 1,
-       .first_conversion_delay = 3,
-       .acquisition_time       = 1,
-       .averaging              = 1,
-       .pen_down_acc_interval  = 1,
+       .stopacq_polarity       = 1,
+       .first_conversion_delay = 3,
+       .acquisition_time       = 1,
+       .averaging              = 1,
+       .pen_down_acc_interval  = 1,
 };
 #endif
 
@@ -701,13 +749,13 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
        .x_plate_ohms           = 620,  /* 620 Ohm from the touch datasheet */
        .pressure_max           = 10000,
        .pressure_min           = 0,
-       .first_conversion_delay = 3,    /* wait 512us before do a first conversion */
-       .acquisition_time       = 1,    /* 4us acquisition time per sample */
+       .first_conversion_delay = 3,    /* wait 512us before do a first conversion */
+       .acquisition_time       = 1,    /* 4us acquisition time per sample */
        .median                 = 2,    /* do 8 measurements */
-       .averaging              = 1,    /* take the average of 4 middle samples */
-       .pen_down_acc_interval  = 255,  /* 9.4 ms */
-       .gpio_output            = 1,    /* configure AUX/VBAT/GPIO as GPIO output */
-       .gpio_default           = 1,    /* During initialization set GPIO = HIGH */
+       .averaging              = 1,    /* take the average of 4 middle samples */
+       .pen_down_acc_interval  = 255,  /* 9.4 ms */
+       .gpio_export            = 1,    /* Export GPIO to gpiolib */
+       .gpio_base              = -1,   /* Dynamic allocation */
 };
 #endif
 
@@ -742,6 +790,11 @@ static const struct adxl34x_platform_data adxl34x_info = {
 /*     .ev_code_act_inactivity = KEY_A,*/      /* EV_KEY */
        .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
        .fifo_mode = ADXL_FIFO_STREAM,
+       .orientation_enable = ADXL_EN_ORIENTATION_3D,
+       .deadzone_angle = ADXL_DEADZONE_ANGLE_10p8,
+       .divisor_length =  ADXL_LP_FILTER_DIVISOR_16,
+       /* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
+       .ev_codes_orient_3d = {BTN_Z, BTN_Y, BTN_X, BTN_A, BTN_B, BTN_C},
 };
 #endif
 
@@ -813,6 +866,35 @@ static struct adf702x_platform_data adf7021_platform_data = {
        .adf702x_regs = adf7021_regs,
        .tx_reg = TXREG,
 };
+static inline void adf702x_mac_init(void)
+{
+       random_ether_addr(adf7021_platform_data.mac_addr);
+}
+#else
+static inline void adf702x_mac_init(void) {}
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+#include <linux/spi/ads7846.h>
+static struct bfin5xx_spi_chip ad7873_spi_chip_info = {
+       .bits_per_word  = 8,
+};
+
+static int ads7873_get_pendown_state(void)
+{
+       return gpio_get_value(GPIO_PF6);
+}
+
+static struct ads7846_platform_data __initdata ad7873_pdata = {
+       .model          = 7873,         /* AD7873 */
+       .x_max          = 0xfff,
+       .y_max          = 0xfff,
+       .x_plate_ohms   = 620,
+       .debounce_max   = 1,
+       .debounce_rep   = 0,
+       .debounce_tol   = (~0),
+       .get_pendown_state = ads7873_get_pendown_state,
+};
 #endif
 
 #if defined(CONFIG_MTD_DATAFLASH) \
@@ -893,24 +975,25 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
-       || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+       || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
        {
-               .modalias = "ad1836",
+               .modalias = "ad183x",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0,
                .chip_select = 4,/* CONFIG_SND_BLACKFIN_SPI_PFBIT */
+               .platform_data = "ad1836", /* only includes chip name for the moment */
                .controller_data = &ad1836_spi_chip_info,
                .mode = SPI_MODE_3,
        },
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD1938) || defined(CONFIG_SND_BF5XX_SOC_AD1938_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD193X) || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE)
        {
-               .modalias = "ad1938",
+               .modalias = "ad193x",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0,
-               .chip_select = 0,/* CONFIG_SND_BLACKFIN_SPI_PFBIT */
+               .chip_select = 5,
                .controller_data = &ad1938_spi_chip_info,
                .mode = SPI_MODE_3,
        },
@@ -929,6 +1012,37 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
+#if defined(CONFIG_AD2S90) || defined(CONFIG_AD2S90_MODULE)
+       {
+               .modalias = "ad2s90",
+               .bus_num = 0,
+               .chip_select = 3,            /* change it for your board */
+               .platform_data = NULL,
+               .controller_data = &ad2s90_spi_chip_info,
+       },
+#endif
+
+#if defined(CONFIG_AD2S120X) || defined(CONFIG_AD2S120X_MODULE)
+       {
+               .modalias = "ad2s120x",
+               .bus_num = 0,
+               .chip_select = 4,            /* CS, change it for your board */
+               .platform_data = ad2s120x_platform_data,
+               .controller_data = &ad2s120x_spi_chip_info,
+       },
+#endif
+
+#if defined(CONFIG_AD2S1210) || defined(CONFIG_AD2S1210_MODULE)
+       {
+               .modalias = "ad2s1210",
+               .max_speed_hz = 8192000,
+               .bus_num = 0,
+               .chip_select = 4,            /* CS, change it for your board */
+               .platform_data = ad2s1210_platform_data,
+               .controller_data = &ad2s1210_spi_chip_info,
+       },
+#endif
+
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
        {
                .modalias = "mmc_spi",
@@ -1016,7 +1130,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .mode = SPI_MODE_0,
        },
 #endif
-
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+       {
+               .modalias = "ads7846",
+               .max_speed_hz = 2000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .irq = IRQ_PF6,
+               .chip_select = GPIO_PF10 + MAX_CTRL_CS, /* GPIO controlled SSEL */
+               .controller_data = &ad7873_spi_chip_info,
+               .platform_data = &ad7873_pdata,
+               .mode = SPI_MODE_0,
+       },
+#endif
 };
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -1132,9 +1257,10 @@ static struct platform_device bfin_fb_device = {
 #include <asm/bfin-lq035q1.h>
 
 static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
-       .mode =         LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
-       .use_bl =       0,      /* let something else control the LCD Blacklight */
-       .gpio_bl =      GPIO_PF7,
+       .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .ppi_mode = USE_RGB565_16_BIT_PPI,
+       .use_bl = 0,    /* let something else control the LCD Blacklight */
+       .gpio_bl = GPIO_PF7,
 };
 
 static struct resource bfin_lq035q1_resources[] = {
@@ -1148,8 +1274,8 @@ static struct resource bfin_lq035q1_resources[] = {
 static struct platform_device bfin_lq035q1_device = {
        .name           = "bfin-lq035q1",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(bfin_lq035q1_resources),
-       .resource       = bfin_lq035q1_resources,
+       .num_resources  = ARRAY_SIZE(bfin_lq035q1_resources),
+       .resource       = bfin_lq035q1_resources,
        .dev            = {
                .platform_data = &bfin_lq035q1_data,
        },
@@ -1157,30 +1283,105 @@ static struct platform_device bfin_lq035q1_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+       {       /* CTS pin */
+               .start = GPIO_PG7,
+               .end = GPIO_PG7,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin */
+               .start = GPIO_PG6,
+               .end = GPIO_PG6,
+               .flags = IORESOURCE_IO,
+       },
+#endif
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
-#endif
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -1260,7 +1461,6 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 #if defined(CONFIG_KEYBOARD_ADP5588) || defined(CONFIG_KEYBOARD_ADP5588_MODULE)
-#include <linux/i2c/adp5588.h>
 static const unsigned short adp5588_keymap[ADP5588_KEYMAPSIZE] = {
        [0]      = KEY_GRAVE,
        [1]      = KEY_1,
@@ -1457,7 +1657,6 @@ static struct adp5520_platform_data adp5520_pdev_data = {
 #endif
 
 #if defined(CONFIG_GPIO_ADP5588) || defined(CONFIG_GPIO_ADP5588_MODULE)
-#include <linux/i2c/adp5588.h>
 static struct adp5588_gpio_platform_data adp5588_gpio_data = {
        .gpio_start = 50,
        .pullup_dis_mask = 0,
@@ -1516,6 +1715,101 @@ static struct adp8870_backlight_platform_data adp8870_pdata = {
 };
 #endif
 
+#if defined(CONFIG_BACKLIGHT_ADP8860) || defined(CONFIG_BACKLIGHT_ADP8860_MODULE)
+#include <linux/i2c/adp8860.h>
+static struct led_info adp8860_leds[] = {
+       {
+               .name = "adp8860-led7",
+               .default_trigger = "none",
+               .flags = ADP8860_LED_D7 | ADP8860_LED_OFFT_600ms,
+       },
+};
+
+static struct adp8860_backlight_platform_data adp8860_pdata = {
+       .bl_led_assign = ADP8860_BL_D1 | ADP8860_BL_D2 | ADP8860_BL_D3 |
+                        ADP8860_BL_D4 | ADP8860_BL_D5 | ADP8860_BL_D6, /* 1 = Backlight 0 = Individual LED */
+
+       .bl_fade_in = ADP8860_FADE_T_1200ms,            /* Backlight Fade-In Timer */
+       .bl_fade_out = ADP8860_FADE_T_1200ms,           /* Backlight Fade-Out Timer */
+       .bl_fade_law = ADP8860_FADE_LAW_CUBIC1,         /* fade-on/fade-off transfer characteristic */
+
+       .en_ambl_sens = 1,                              /* 1 = enable ambient light sensor */
+       .abml_filt = ADP8860_BL_AMBL_FILT_320ms,        /* Light sensor filter time */
+
+       .l1_daylight_max = ADP8860_BL_CUR_mA(20),       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       .l1_daylight_dim = ADP8860_BL_CUR_mA(0),        /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       .l2_office_max = ADP8860_BL_CUR_mA(6),          /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       .l2_office_dim = ADP8860_BL_CUR_mA(0),          /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       .l3_dark_max = ADP8860_BL_CUR_mA(2),            /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       .l3_dark_dim = ADP8860_BL_CUR_mA(0),            /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+
+       .l2_trip = ADP8860_L2_COMP_CURR_uA(710),        /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       .l2_hyst = ADP8860_L2_COMP_CURR_uA(73),         /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       .l3_trip = ADP8860_L3_COMP_CURR_uA(43),         /* use L3_COMP_CURR_uA(I) 0 <= I <= 138 uA */
+       .l3_hyst = ADP8860_L3_COMP_CURR_uA(11),         /* use L3_COMP_CURR_uA(I) 0 <= I <= 138 uA */
+
+       .leds = adp8860_leds,
+       .num_leds = ARRAY_SIZE(adp8860_leds),
+       .led_fade_law = ADP8860_FADE_LAW_SQUARE,        /* fade-on/fade-off transfer characteristic */
+       .led_fade_in = ADP8860_FADE_T_600ms,
+       .led_fade_out = ADP8860_FADE_T_600ms,
+       .led_on_time = ADP8860_LED_ONT_200ms,
+};
+#endif
+
+#if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
+static struct regulator_consumer_supply ad5398_consumer = {
+       .supply = "current",
+};
+
+static struct regulator_init_data ad5398_regulator_data = {
+       .constraints = {
+               .name = "current range",
+               .max_uA = 120000,
+               .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = 1,
+       .consumer_supplies     = &ad5398_consumer,
+};
+
+static struct ad5398_platform_data ad5398_i2c_platform_data = {
+       .current_bits = 10,
+       .current_offset = 4,
+       .regulator_data = &ad5398_regulator_data,
+};
+
+#if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
+       defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
+static struct platform_device ad5398_virt_consumer_device = {
+       .name = "reg-virt-consumer",
+       .id = 0,
+       .dev = {
+               .platform_data = "current", /* Passed to driver */
+       },
+};
+#endif
+#if defined(CONFIG_REGULATOR_USERSPACE_CONSUMER) || \
+       defined(CONFIG_REGULATOR_USERSPACE_CONSUMER_MODULE)
+static struct regulator_bulk_data ad5398_bulk_data = {
+       .supply = "current",
+};
+
+static struct regulator_userspace_consumer_data ad5398_userspace_comsumer_data = {
+       .name = "ad5398",
+       .num_supplies = 1,
+       .supplies = &ad5398_bulk_data,
+};
+
+static struct platform_device ad5398_userspace_consumer_device = {
+       .name = "reg-userspace-consumer",
+       .id = 0,
+       .dev = {
+               .platform_data = &ad5398_userspace_comsumer_data,
+       },
+};
+#endif
+#endif
+
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #if defined(CONFIG_INPUT_AD714X_I2C) || defined(CONFIG_INPUT_AD714X_I2C_MODULE)
        {
@@ -1524,6 +1818,52 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                .platform_data = (void *)&ad7142_i2c_platform_data,
        },
 #endif
+
+#if defined(CONFIG_AD7150) || defined(CONFIG_AD7150_MODULE)
+       {
+               I2C_BOARD_INFO("ad7150", 0x48),
+               .irq = IRQ_PG5, /* fixme: use real interrupt number */
+       },
+#endif
+
+#if defined(CONFIG_AD7152) || defined(CONFIG_AD7152_MODULE)
+       {
+               I2C_BOARD_INFO("ad7152", 0x48),
+       },
+#endif
+
+#if defined(CONFIG_AD774X) || defined(CONFIG_AD774X_MODULE)
+       {
+               I2C_BOARD_INFO("ad774x", 0x48),
+       },
+#endif
+
+#if defined(CONFIG_AD7414) || defined(CONFIG_AD7414_MODULE)
+       {
+               I2C_BOARD_INFO("ad7414", 0x9),
+               .irq = IRQ_PG5,
+               /*
+                * platform_data pointer is borrwoed by the driver to
+                * store custimer defined IRQ ALART level mode.
+                * only IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW are valid.
+                */
+               .platform_data = (void *)IRQF_TRIGGER_LOW,
+       },
+#endif
+
+#if defined(CONFIG_AD7416) || defined(CONFIG_AD7416_MODULE)
+       {
+               I2C_BOARD_INFO("ad7417", 0xb),
+               .irq = IRQ_PG5,
+               /*
+                * platform_data pointer is borrwoed by the driver to
+                * store custimer defined IRQ ALART level mode.
+                * only IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW are valid.
+                */
+               .platform_data = (void *)IRQF_TRIGGER_LOW,
+       },
+#endif
+
 #if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
@@ -1595,24 +1935,105 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                I2C_BOARD_INFO("adau1761", 0x38),
        },
 #endif
+#if defined(CONFIG_SND_SOC_ADAU1361) || defined(CONFIG_SND_SOC_ADAU1361_MODULE)
+       {
+               I2C_BOARD_INFO("adau1361", 0x38),
+       },
+#endif
 #if defined(CONFIG_AD525X_DPOT) || defined(CONFIG_AD525X_DPOT_MODULE)
        {
                I2C_BOARD_INFO("ad5258", 0x18),
        },
 #endif
+#if defined(CONFIG_SND_SOC_SSM2602) || defined(CONFIG_SND_SOC_SSM2602_MODULE)
+       {
+               I2C_BOARD_INFO("ssm2602", 0x1b),
+       },
+#endif
+#if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
+       {
+               I2C_BOARD_INFO("ad5398", 0xC),
+               .platform_data = (void *)&ad5398_i2c_platform_data,
+       },
+#endif
+#if defined(CONFIG_BACKLIGHT_ADP8860) || defined(CONFIG_BACKLIGHT_ADP8860_MODULE)
+       {
+               I2C_BOARD_INFO("adp8860", 0x2A),
+               .platform_data = (void *)&adp8860_pdata,
+       },
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 #define CF_IDE_NAND_CARD_USE_HDD_INTERFACE
@@ -1701,13 +2122,121 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+       .name = "bfin-i2s",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
        /* TODO: add platform data here */
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97 = {
+       .name = "bfin-ac97",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_REGULATOR_ADP_SWITCH) || defined(CONFIG_REGULATOR_ADP_SWITCH_MODULE)
+#define REGULATOR_ADP122        "adp122"
+#define REGULATOR_ADP150        "adp150"
+
+static struct regulator_consumer_supply adp122_consumers = {
+               .supply = REGULATOR_ADP122,
+};
+
+static struct regulator_consumer_supply adp150_consumers = {
+               .supply = REGULATOR_ADP150,
+};
+
+static struct regulator_init_data adp_switch_regulator_data[] = {
+       {
+               .constraints = {
+                       .name = REGULATOR_ADP122,
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                       .min_uA = 0,
+                       .max_uA = 300000,
+               },
+               .num_consumer_supplies = 1,     /* only 1 */
+               .consumer_supplies     = &adp122_consumers,
+               .driver_data           = (void *)GPIO_PF2, /* gpio port only */
+       },
+       {
+               .constraints = {
+                       .name = REGULATOR_ADP150,
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                       .min_uA = 0,
+                       .max_uA = 150000,
+               },
+               .num_consumer_supplies = 1,     /* only 1 */
+               .consumer_supplies     = &adp150_consumers,
+               .driver_data           = (void *)GPIO_PF3, /* gpio port only */
+       },
+};
+
+static struct adp_switch_platform_data adp_switch_pdata = {
+       .regulator_num = ARRAY_SIZE(adp_switch_regulator_data),
+       .regulator_data = adp_switch_regulator_data,
+};
+
+static struct platform_device adp_switch_device = {
+       .name = "adp_switch",
+       .id = 0,
+       .dev = {
+               .platform_data = &adp_switch_pdata,
+       },
+};
+
+#if defined(CONFIG_REGULATOR_USERSPACE_CONSUMER) || \
+       defined(CONFIG_REGULATOR_USERSPACE_CONSUMER_MODULE)
+static struct regulator_bulk_data adp122_bulk_data = {
+       .supply = REGULATOR_ADP122,
+};
+
+static struct regulator_userspace_consumer_data adp122_userspace_comsumer_data = {
+       .name = REGULATOR_ADP122,
+       .num_supplies = 1,
+       .supplies = &adp122_bulk_data,
+};
+
+static struct platform_device adp122_userspace_consumer_device = {
+       .name = "reg-userspace-consumer",
+       .id = 0,
+       .dev = {
+               .platform_data = &adp122_userspace_comsumer_data,
+       },
+};
+
+static struct regulator_bulk_data adp150_bulk_data = {
+       .supply = REGULATOR_ADP150,
+};
+
+static struct regulator_userspace_consumer_data adp150_userspace_comsumer_data = {
+       .name = REGULATOR_ADP150,
+       .num_supplies = 1,
+       .supplies = &adp150_bulk_data,
+};
+
+static struct platform_device adp150_userspace_consumer_device = {
+       .name = "reg-userspace-consumer",
+       .id = 1,
+       .dev = {
+               .platform_data = &adp150_userspace_comsumer_data,
+       },
+};
+#endif
+#endif
+
+
 static struct platform_device *stamp_devices[] __initdata = {
 
        &bfin_dpmc,
@@ -1771,7 +2300,12 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -1788,9 +2322,13 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
        &bfin_pata_device,
@@ -1808,18 +2346,46 @@ static struct platform_device *stamp_devices[] __initdata = {
        &stamp_flash_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
        &bfin_tdm,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_ac97,
+#endif
+#if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
+#if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
+       defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
+       &ad5398_virt_consumer_device,
+#endif
+#if defined(CONFIG_REGULATOR_USERSPACE_CONSUMER) || \
+       defined(CONFIG_REGULATOR_USERSPACE_CONSUMER_MODULE)
+       &ad5398_userspace_consumer_device,
+#endif
+#endif
+
+#if defined(CONFIG_REGULATOR_ADP_SWITCH) || defined(CONFIG_REGULATOR_ADP_SWITCH_MODULE)
+       &adp_switch_device,
+#if defined(CONFIG_REGULATOR_USERSPACE_CONSUMER) || \
+       defined(CONFIG_REGULATOR_USERSPACE_CONSUMER_MODULE)
+       &adp122_userspace_consumer_device,
+       &adp150_userspace_consumer_device,
+#endif
+#endif
 };
 
 static int __init stamp_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
-       i2c_register_board_info(0, bfin_i2c_board_info,
-                               ARRAY_SIZE(bfin_i2c_board_info));
        bfin_plat_nand_init();
+       adf702x_mac_init();
        platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+       i2c_register_board_info(0, bfin_i2c_board_info,
+                               ARRAY_SIZE(bfin_i2c_board_info));
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 
        return 0;
@@ -1827,6 +2393,34 @@ static int __init stamp_init(void)
 
 arch_initcall(stamp_init);
 
+
+static struct platform_device *stamp_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(stamp_early_devices,
+               ARRAY_SIZE(stamp_early_devices));
+}
+
 void native_machine_restart(char *cmd)
 {
        /* workaround reboot hang when booting from SPI */
index 57163b6..4f0a2e7 100644 (file)
@@ -74,7 +74,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -113,7 +113,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -327,25 +327,93 @@ static struct platform_device cm_flash_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
-       }, {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+       },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+       {
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart1_device = {
        .name = "bfin-uart",
        .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -425,16 +493,75 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
 static struct platform_device bfin_sport0_uart_device = {
        .name = "bfin-sport-uart",
        .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
 };
 
 static struct platform_device bfin_sport1_uart_device = {
        .name = "bfin-sport-uart",
        .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static struct platform_device bfin_mii_bus = {
@@ -524,7 +651,12 @@ static struct platform_device *cm_bf537_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -541,9 +673,13 @@ static struct platform_device *cm_bf537_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
        &bfin_sport1_uart_device,
 #endif
+#endif
 
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
        &isp1362_hcd_device,
@@ -591,6 +727,33 @@ static int __init tcm_bf537_init(void)
 
 arch_initcall(tcm_bf537_init);
 
+static struct platform_device *cm_bf537_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf537_early_devices,
+               ARRAY_SIZE(cm_bf537_early_devices));
+}
+
 void bfin_get_ether_addr(char *addr)
 {
        random_ether_addr(addr);
index 0defa94..789a4f2 100644 (file)
 
 #define GPIO_IRQ_BASE  IRQ_PF0
 
-#define NR_IRQS     (IRQ_PH15+1)
+#define IRQ_MAC_PHYINT         98 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         99 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                100 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                101 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                102 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       103 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       104 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                105 /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
+#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7            7
 #define IVG8            8
index c296bb1..1a1f658 100644 (file)
@@ -41,37 +41,148 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_THR,
+               .end = UART0_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+       {       /* CTS pin */
+               .start = GPIO_PG7,
+               .end = GPIO_PG7,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin */
+               .start = GPIO_PG6,
+               .end = GPIO_PG6,
+               .flags = IORESOURCE_IO,
+       },
+#endif
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_THR,
+               .end = UART1_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART2
+static struct resource bfin_uart2_resources[] = {
        {
-               .start = 0xFFC02100,
-               .end = 0xFFC021FF,
+               .start = UART2_THR,
+               .end = UART2_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
-#endif
+       {
+               .start = IRQ_UART2_RX,
+               .end = IRQ_UART2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART2_ERROR,
+               .end = IRQ_UART2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART2_TX,
+               .end = CH_UART2_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART2_RX,
+               .end = CH_UART2_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart2_peripherals[] = {
+       P_UART2_TX, P_UART2_RX, 0
 };
 
-static struct platform_device bfin_uart_device = {
+static struct platform_device bfin_uart2_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_uart2_resources),
+       .resource = bfin_uart2_resources,
+       .dev = {
+               .platform_data = &bfin_uart2_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -151,6 +262,145 @@ static struct platform_device bfin_sir2_device = {
 #endif
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+static struct resource bfin_sport2_uart_resources[] = {
+       {
+               .start = SPORT2_TCR1,
+               .end = SPORT2_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT2_RX,
+               .end = IRQ_SPORT2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT2_ERROR,
+               .end = IRQ_SPORT2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport2_peripherals[] = {
+       P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
+       P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0
+};
+
+static struct platform_device bfin_sport2_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_sport2_uart_resources),
+       .resource = bfin_sport2_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport2_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+static struct resource bfin_sport3_uart_resources[] = {
+       {
+               .start = SPORT3_TCR1,
+               .end = SPORT3_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT3_RX,
+               .end = IRQ_SPORT3_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT3_ERROR,
+               .end = IRQ_SPORT3_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport3_peripherals[] = {
+       P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
+       P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0
+};
+
+static struct platform_device bfin_sport3_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 3,
+       .num_resources = ARRAY_SIZE(bfin_sport3_uart_resources),
+       .resource = bfin_sport3_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport3_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
 unsigned short bfin_can_peripherals[] = {
        P_CAN0_RX, P_CAN0_TX, 0
@@ -268,8 +518,8 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
        .median                 = 2,    /* do 8 measurements */
        .averaging              = 1,    /* take the average of 4 middle samples */
        .pen_down_acc_interval  = 255,  /* 9.4 ms */
-       .gpio_output            = 1,    /* configure AUX/VBAT/GPIO as GPIO output */
-       .gpio_default           = 1,    /* During initialization set GPIO = HIGH */
+       .gpio_export            = 1,    /* Export GPIO to gpiolib */
+       .gpio_base              = -1,   /* Dynamic allocation */
 };
 #endif
 
@@ -284,9 +534,10 @@ static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
 #include <asm/bfin-lq035q1.h>
 
 static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
-       .mode =         LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
-       .use_bl =       0,      /* let something else control the LCD Blacklight */
-       .gpio_bl =      GPIO_PF7,
+       .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .ppi_mode = USE_RGB565_16_BIT_PPI,
+       .use_bl = 0,    /* let something else control the LCD Blacklight */
+       .gpio_bl = GPIO_PF7,
 };
 
 static struct resource bfin_lq035q1_resources[] = {
@@ -622,7 +873,15 @@ static struct platform_device *cm_bf538_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
 #endif
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -648,6 +907,21 @@ static struct platform_device *cm_bf538_devices[] __initdata = {
 #endif
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
        &bfin_can_device,
 #endif
@@ -683,3 +957,39 @@ static int __init ezkit_init(void)
 }
 
 arch_initcall(ezkit_init);
+
+static struct platform_device *ezkit_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezkit_early_devices,
+               ARRAY_SIZE(ezkit_early_devices));
+}
index a4b7fcb..7a479d2 100644 (file)
 
 #define GPIO_IRQ_BASE  IRQ_PF0
 
-#define NR_IRQS     (IRQ_PF15+1)
+#define NR_MACH_IRQS   (IRQ_PF15 + 1)
+#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7            7
 #define IVG8            8
index ccdcd6d..f60c333 100644 (file)
@@ -127,44 +127,211 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_DLL,
+               .end = UART0_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_DLL,
+               .end = UART1_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       {       /* CTS pin -- 0 means not supported */
+               .start = GPIO_PE10,
+               .end = GPIO_PE10,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin -- 0 means not supported */
+               .start = GPIO_PE9,
+               .end = GPIO_PE9,
+               .flags = IORESOURCE_IO,
+       },
+#endif
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       P_UART1_RTS, P_UART1_CTS,
+#endif
+       0
+};
+
+static struct platform_device bfin_uart1_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART2
+static struct resource bfin_uart2_resources[] = {
        {
-               .start = 0xFFC02100,
-               .end = 0xFFC021FF,
+               .start = UART2_DLL,
+               .end = UART2_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART2_RX,
+               .end = IRQ_UART2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART2_ERROR,
+               .end = IRQ_UART2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART2_TX,
+               .end = CH_UART2_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART2_RX,
+               .end = CH_UART2_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart2_peripherals[] = {
+       P_UART2_TX, P_UART2_RX, 0
+};
+
+static struct platform_device bfin_uart2_device = {
+       .name = "bfin-uart",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_uart2_resources),
+       .resource = bfin_uart2_resources,
+       .dev = {
+               .platform_data = &bfin_uart2_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART3
+static struct resource bfin_uart3_resources[] = {
        {
-               .start = 0xFFC03100,
-               .end = 0xFFC031FF,
+               .start = UART3_DLL,
+               .end = UART3_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART3_RX,
+               .end = IRQ_UART3_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART3_ERROR,
+               .end = IRQ_UART3_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART3_TX,
+               .end = CH_UART3_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART3_RX,
+               .end = CH_UART3_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+       {       /* CTS pin -- 0 means not supported */
+               .start = GPIO_PB3,
+               .end = GPIO_PB3,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin -- 0 means not supported */
+               .start = GPIO_PB2,
+               .end = GPIO_PB2,
+               .flags = IORESOURCE_IO,
+       },
 #endif
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart3_peripherals[] = {
+       P_UART3_TX, P_UART3_RX,
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+       P_UART3_RTS, P_UART3_CTS,
+#endif
+       0
+};
+
+static struct platform_device bfin_uart3_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 3,
+       .num_resources = ARRAY_SIZE(bfin_uart3_resources),
+       .resource = bfin_uart3_resources,
+       .dev = {
+               .platform_data = &bfin_uart3_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -359,6 +526,145 @@ static struct platform_device musb_device = {
 };
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+static struct resource bfin_sport2_uart_resources[] = {
+       {
+               .start = SPORT2_TCR1,
+               .end = SPORT2_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT2_RX,
+               .end = IRQ_SPORT2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT2_ERROR,
+               .end = IRQ_SPORT2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport2_peripherals[] = {
+       P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
+       P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0
+};
+
+static struct platform_device bfin_sport2_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_sport2_uart_resources),
+       .resource = bfin_sport2_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport2_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+static struct resource bfin_sport3_uart_resources[] = {
+       {
+               .start = SPORT3_TCR1,
+               .end = SPORT3_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT3_RX,
+               .end = IRQ_SPORT3_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT3_ERROR,
+               .end = IRQ_SPORT3_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport3_peripherals[] = {
+       P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
+       P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0
+};
+
+static struct platform_device bfin_sport3_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 3,
+       .num_resources = ARRAY_SIZE(bfin_sport3_uart_resources),
+       .resource = bfin_sport3_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport3_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
 #if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
 static struct resource bfin_atapi_resources[] = {
        {
@@ -752,7 +1058,18 @@ static struct platform_device *cm_bf548_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+       &bfin_uart3_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -782,6 +1099,21 @@ static struct platform_device *cm_bf548_devices[] __initdata = {
        &musb_device,
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+
 #if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
        &bfin_atapi_device,
 #endif
@@ -833,3 +1165,42 @@ static int __init cm_bf548_init(void)
 }
 
 arch_initcall(cm_bf548_init);
+
+static struct platform_device *cm_bf548_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+       &bfin_uart3_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf548_early_devices,
+               ARRAY_SIZE(cm_bf548_early_devices));
+}
index 60193f7..06919db 100644 (file)
@@ -232,44 +232,211 @@ static struct platform_device rtc_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = UART0_DLL,
+               .end = UART0_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART0_RX,
+               .end = IRQ_UART0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART0_ERROR,
+               .end = IRQ_UART0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART0_TX,
+               .end = CH_UART0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART0_RX,
+               .end = CH_UART0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
        {
-               .start = 0xFFC02000,
-               .end = 0xFFC020FF,
+               .start = UART1_DLL,
+               .end = UART1_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART1_RX,
+               .end = IRQ_UART1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART1_ERROR,
+               .end = IRQ_UART1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART1_TX,
+               .end = CH_UART1_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART1_RX,
+               .end = CH_UART1_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       {       /* CTS pin -- 0 means not supported */
+               .start = GPIO_PE10,
+               .end = GPIO_PE10,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin -- 0 means not supported */
+               .start = GPIO_PE9,
+               .end = GPIO_PE9,
+               .flags = IORESOURCE_IO,
+       },
+#endif
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+       P_UART1_TX, P_UART1_RX,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+       P_UART1_RTS, P_UART1_CTS,
+#endif
+       0
+};
+
+static struct platform_device bfin_uart1_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart1_resources),
+       .resource = bfin_uart1_resources,
+       .dev = {
+               .platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART2
+static struct resource bfin_uart2_resources[] = {
        {
-               .start = 0xFFC02100,
-               .end = 0xFFC021FF,
+               .start = UART2_DLL,
+               .end = UART2_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART2_RX,
+               .end = IRQ_UART2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART2_ERROR,
+               .end = IRQ_UART2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART2_TX,
+               .end = CH_UART2_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART2_RX,
+               .end = CH_UART2_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart2_peripherals[] = {
+       P_UART2_TX, P_UART2_RX, 0
+};
+
+static struct platform_device bfin_uart2_device = {
+       .name = "bfin-uart",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_uart2_resources),
+       .resource = bfin_uart2_resources,
+       .dev = {
+               .platform_data = &bfin_uart2_peripherals, /* Passed to driver */
+       },
+};
 #endif
 #ifdef CONFIG_SERIAL_BFIN_UART3
+static struct resource bfin_uart3_resources[] = {
        {
-               .start = 0xFFC03100,
-               .end = 0xFFC031FF,
+               .start = UART3_DLL,
+               .end = UART3_RBR+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART3_RX,
+               .end = IRQ_UART3_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART3_ERROR,
+               .end = IRQ_UART3_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART3_TX,
+               .end = CH_UART3_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART3_RX,
+               .end = CH_UART3_RX,
+               .flags = IORESOURCE_DMA,
+       },
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+       {       /* CTS pin -- 0 means not supported */
+               .start = GPIO_PB3,
+               .end = GPIO_PB3,
+               .flags = IORESOURCE_IO,
+       },
+       {       /* RTS pin -- 0 means not supported */
+               .start = GPIO_PB2,
+               .end = GPIO_PB2,
+               .flags = IORESOURCE_IO,
+       },
 #endif
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart3_peripherals[] = {
+       P_UART3_TX, P_UART3_RX,
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+       P_UART3_RTS, P_UART3_CTS,
+#endif
+       0
+};
+
+static struct platform_device bfin_uart3_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 3,
+       .num_resources = ARRAY_SIZE(bfin_uart3_resources),
+       .resource = bfin_uart3_resources,
+       .dev = {
+               .platform_data = &bfin_uart3_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -464,6 +631,145 @@ static struct platform_device musb_device = {
 };
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+       P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+       .resource = bfin_sport0_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+       {
+               .start = SPORT1_TCR1,
+               .end = SPORT1_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT1_RX,
+               .end = IRQ_SPORT1_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT1_ERROR,
+               .end = IRQ_SPORT1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+       P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+       .resource = bfin_sport1_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+static struct resource bfin_sport2_uart_resources[] = {
+       {
+               .start = SPORT2_TCR1,
+               .end = SPORT2_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT2_RX,
+               .end = IRQ_SPORT2_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT2_ERROR,
+               .end = IRQ_SPORT2_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport2_peripherals[] = {
+       P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
+       P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0
+};
+
+static struct platform_device bfin_sport2_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(bfin_sport2_uart_resources),
+       .resource = bfin_sport2_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport2_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+static struct resource bfin_sport3_uart_resources[] = {
+       {
+               .start = SPORT3_TCR1,
+               .end = SPORT3_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT3_RX,
+               .end = IRQ_SPORT3_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT3_ERROR,
+               .end = IRQ_SPORT3_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+unsigned short bfin_sport3_peripherals[] = {
+       P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
+       P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0
+};
+
+static struct platform_device bfin_sport3_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 3,
+       .num_resources = ARRAY_SIZE(bfin_sport3_uart_resources),
+       .resource = bfin_sport3_uart_resources,
+       .dev = {
+               .platform_data = &bfin_sport3_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
 unsigned short bfin_can_peripherals[] = {
        P_CAN0_RX, P_CAN0_TX, 0
@@ -657,8 +963,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -714,8 +1020,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .mode = SPI_MODE_3,
        },
 #endif
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -951,6 +1257,30 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+       .name = "bfin-i2s",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+       .name = "bfin-tdm",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97 = {
+       .name = "bfin-ac97",
+       .id = CONFIG_SND_BF5XX_SPORT_NUM,
+       /* TODO: add platform data here */
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 
        &bfin_dpmc,
@@ -960,7 +1290,18 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+       &bfin_uart3_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -994,6 +1335,21 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_isp1760_device,
 #endif
 
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
        &bfin_can_device,
 #endif
@@ -1037,6 +1393,18 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
        &ezkit_flash_device,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_tdm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_ac97,
+#endif
 };
 
 static int __init ezkit_init(void)
@@ -1058,3 +1426,42 @@ static int __init ezkit_init(void)
 }
 
 arch_initcall(ezkit_init);
+
+static struct platform_device *ezkit_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       &bfin_uart1_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       &bfin_uart2_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+       &bfin_uart3_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+       &bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+       &bfin_sport1_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+       &bfin_sport2_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+       &bfin_sport3_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezkit_early_devices,
+               ARRAY_SIZE(ezkit_early_devices));
+}
index 106db05..1f99b51 100644 (file)
@@ -317,7 +317,8 @@ Events         (highest priority)  EMU         0
 
 #define GPIO_IRQ_BASE  IRQ_PA0
 
-#define NR_IRQS     (IRQ_PJ15+1)
+#define NR_MACH_IRQS   (IRQ_PJ15 + 1)
+#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 /* For compatibility reasons with existing code */
 
index 59e18af..b340297 100644 (file)
@@ -6,3 +6,4 @@ obj-y := ints-priority.o dma.o
 
 obj-$(CONFIG_BF561_COREB) += coreb.o
 obj-$(CONFIG_SMP)  += smp.o secondary.o atomic.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
index 07e8dc8..5163e2c 100644 (file)
@@ -176,7 +176,7 @@ static struct resource smsc911x_resources[] = {
 };
 
 static struct smsc911x_platform_config smsc911x_config = {
-       .flags = SMSC911X_USE_32BIT,
+       .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
        .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
        .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
        .phy_interface = PHY_INTERFACE_MODE_MII,
index dfc8d5b..e127aed 100644 (file)
@@ -72,7 +72,7 @@ static struct bfin5xx_spi_chip spi_adc_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -111,7 +111,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -305,21 +305,50 @@ static struct platform_device isp1362_hcd_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART_RX,
+               .end = IRQ_UART_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART_ERROR,
+               .end = IRQ_UART_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART_TX,
+               .end = CH_UART_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART_RX,
+               .end = CH_UART_RX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -463,7 +492,9 @@ static struct platform_device *cm_bf561_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -516,3 +547,18 @@ static int __init cm_bf561_init(void)
 }
 
 arch_initcall(cm_bf561_init);
+
+static struct platform_device *cm_bf561_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(cm_bf561_early_devices,
+               ARRAY_SIZE(cm_bf561_early_devices));
+}
index ffd3e6a..9b93e2f 100644 (file)
@@ -160,21 +160,50 @@ static struct platform_device smc91x_device = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
        {
-               .start = 0xFFC00400,
-               .end = 0xFFC004FF,
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .start = IRQ_UART_RX,
+               .end = IRQ_UART_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART_ERROR,
+               .end = IRQ_UART_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART_TX,
+               .end = CH_UART_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART_RX,
+               .end = CH_UART_RX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
-static struct platform_device bfin_uart_device = {
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
        .name = "bfin-uart",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(bfin_uart_resources),
-       .resource = bfin_uart_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
 };
 #endif
+#endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
@@ -245,8 +274,8 @@ static struct platform_device ezkit_flash_device = {
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -299,8 +328,8 @@ static struct platform_device bfin_spi0_device = {
 #endif
 
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
-#if defined(CONFIG_SND_BLACKFIN_AD1836) \
-       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+#if defined(CONFIG_SND_BLACKFIN_AD183X) \
+       || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
        {
                .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -412,7 +441,9 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
-       &bfin_uart_device,
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
 #endif
 
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
@@ -458,3 +489,18 @@ static int __init ezkit_init(void)
 }
 
 arch_initcall(ezkit_init);
+
+static struct platform_device *ezkit_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(ezkit_early_devices,
+               ARRAY_SIZE(ezkit_early_devices));
+}
index 8ba7252..d3017e5 100644 (file)
@@ -42,6 +42,52 @@ static struct platform_device smc91x_device = {
        .resource      = smc91x_resources,
 };
 
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
+       {
+               .start = BFIN_UART_THR,
+               .end = BFIN_UART_GCTL+2,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_UART_RX,
+               .end = IRQ_UART_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_UART_ERROR,
+               .end = IRQ_UART_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_UART_TX,
+               .end = CH_UART_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_UART_RX,
+               .end = CH_UART_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+       P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+       .name = "bfin-uart",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_uart0_resources),
+       .resource = bfin_uart0_resources,
+       .dev = {
+               .platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+       },
+};
+#endif
+#endif
+
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
 static struct resource bfin_sir0_resources[] = {
@@ -73,6 +119,13 @@ static struct platform_device bfin_sir0_device = {
 
 static struct platform_device *tepla_devices[] __initdata = {
        &smc91x_device,
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+
 #if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
 #ifdef CONFIG_BFIN_SIR0
        &bfin_sir0_device,
@@ -87,3 +140,18 @@ static int __init tepla_init(void)
 }
 
 arch_initcall(tepla_init);
+
+static struct platform_device *tepla_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       &bfin_uart0_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+       printk(KERN_INFO "register early platform devices\n");
+       early_platform_add_devices(tepla_early_devices,
+               ARRAY_SIZE(tepla_early_devices));
+}
diff --git a/arch/blackfin/mach-bf561/hotplug.c b/arch/blackfin/mach-bf561/hotplug.c
new file mode 100644 (file)
index 0000000..c95169b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *               Graff Yang <graf.yang@analog.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <asm/blackfin.h>
+#include <asm/smp.h>
+#define SIC_SYSIRQ(irq)        (irq - (IRQ_CORETMR + 1))
+
+int hotplug_coreb;
+
+void platform_cpu_die(void)
+{
+       unsigned long iwr[2] = {0, 0};
+       unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
+       unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
+
+       hotplug_coreb = 1;
+
+       iwr[bank] = bit;
+
+       /* disable core timer */
+       bfin_write_TCNTL(0);
+
+       /* clear ipi interrupt IRQ_SUPPLE_0 */
+       bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
+       SSYNC();
+
+       coreb_sleep(iwr[0], iwr[1], 0);
+}
index 7b208db..c95566a 100644 (file)
 
 #define GPIO_IRQ_BASE          IRQ_PF0
 
-#define NR_IRQS                        (IRQ_PF47 + 1)
+#define NR_MACH_IRQS           (IRQ_PF47 + 1)
+#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #define IVG7                   7
 #define IVG8                   8
index 390c7f4..2c8c514 100644 (file)
@@ -25,4 +25,6 @@ void platform_send_ipi_cpu(unsigned int cpu);
 
 void platform_clear_ipi(unsigned int cpu);
 
+void bfin_local_timer_setup(void);
+
 #endif /* !_MACH_BF561_SMP */
index 8e60503..4624eeb 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <asm/blackfin.h>
 #include <asm/asm-offsets.h>
+#include <asm/trace.h>
 
 __INIT
 
@@ -62,6 +63,8 @@ ENTRY(_coreb_trampoline_start)
        M2 = r0;
        M3 = r0;
 
+       trace_buffer_init(p0,r0);
+
        /* Turn off the icache */
        p0.l = LO(IMEM_CONTROL);
        p0.h = HI(IMEM_CONTROL);
@@ -159,6 +162,41 @@ ENTRY(_coreb_trampoline_start)
 ENDPROC(_coreb_trampoline_start)
 ENTRY(_coreb_trampoline_end)
 
+.section ".text"
+ENTRY(_set_sicb_iwr)
+       P0.H = hi(SICB_IWR0);
+       P0.L = lo(SICB_IWR0);
+       P1.H = hi(SICB_IWR1);
+       P1.L = lo(SICB_IWR1);
+       [P0] = R0;
+       [P1] = R1;
+       SSYNC;
+       RTS;
+ENDPROC(_set_sicb_iwr)
+
+ENTRY(_coreb_sleep)
+       sp.l = lo(INITIAL_STACK);
+       sp.h = hi(INITIAL_STACK);
+       fp = sp;
+       usp = sp;
+
+       call _set_sicb_iwr;
+
+       CLI R2;
+       SSYNC;
+       IDLE;
+       STI R2;
+
+       R0 = IWR_DISABLE_ALL;
+       R1 = IWR_DISABLE_ALL;
+       call _set_sicb_iwr;
+
+       p0.h = hi(COREB_L1_CODE_START);
+       p0.l = lo(COREB_L1_CODE_START);
+       jump (p0);
+ENDPROC(_coreb_sleep)
+
+__CPUINIT
 ENTRY(_coreb_start)
        [--sp] = reti;
 
@@ -176,12 +214,20 @@ ENTRY(_coreb_start)
        sp = [p0];
        usp = sp;
        fp = sp;
+#ifdef CONFIG_HOTPLUG_CPU
+       p0.l = _hotplug_coreb;
+       p0.h = _hotplug_coreb;
+       r0 = [p0];
+       cc = BITTST(r0, 0);
+       if cc jump 3f;
+#endif
        sp += -12;
        call _init_pda
        sp += 12;
+#ifdef CONFIG_HOTPLUG_CPU
+3:
+#endif
        call _secondary_start_kernel;
 .L_exit:
        jump.s  .L_exit;
 ENDPROC(_coreb_start)
-
-__FINIT
index 0192532..3b9a4bf 100644 (file)
 #include <linux/delay.h>
 #include <asm/smp.h>
 #include <asm/dma.h>
+#include <asm/time.h>
 
 static DEFINE_SPINLOCK(boot_lock);
 
-static cpumask_t cpu_callin_map;
-
 /*
  * platform_init_cpus() - Tell the world about how many cores we
  * have. This is called while setting up the architecture support
@@ -66,13 +65,15 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
        bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
        bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
        bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
+       bfin_write_SICB_IWR0(IWR_DISABLE_ALL);
+       bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
        SSYNC();
 
        /* Store CPU-private information to the cpu_data array. */
        bfin_setup_cpudata(cpu);
 
        /* We are done with local CPU inits, unblock the boot CPU. */
-       cpu_set(cpu, cpu_callin_map);
+       set_cpu_online(cpu, true);
        spin_lock(&boot_lock);
        spin_unlock(&boot_lock);
 }
@@ -81,28 +82,28 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
 {
        unsigned long timeout;
 
-       /* CoreB already running?! */
-       BUG_ON((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0);
-
        printk(KERN_INFO "Booting Core B.\n");
 
        spin_lock(&boot_lock);
 
-       /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
-       SSYNC();
-       bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
-       SSYNC();
+       if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0) {
+               /* CoreB already running, sending ipi to wakeup it */
+               platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
+       } else {
+               /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
+               bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
+               SSYNC();
+       }
 
        timeout = jiffies + 1 * HZ;
        while (time_before(jiffies, timeout)) {
-               if (cpu_isset(cpu, cpu_callin_map))
+               if (cpu_online(cpu))
                        break;
                udelay(100);
                barrier();
        }
 
-       if (cpu_isset(cpu, cpu_callin_map)) {
-               cpu_set(cpu, cpu_online_map);
+       if (cpu_online(cpu)) {
                /* release the lock and let coreb run */
                spin_unlock(&boot_lock);
                return 0;
@@ -147,3 +148,20 @@ void platform_clear_ipi(unsigned int cpu)
        bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + cpu)));
        SSYNC();
 }
+
+/*
+ * Setup core B's local core timer.
+ * In SMP, core timer is used for clock event device.
+ */
+void __cpuinit bfin_local_timer_setup(void)
+{
+#if defined(CONFIG_TICKSOURCE_CORETMR)
+       bfin_coretmr_init();
+       bfin_coretmr_clockevent_init();
+       get_irq_chip(IRQ_CORETMR)->unmask(IRQ_CORETMR);
+#else
+       /* Power down the core timer, just to play safe. */
+       bfin_write_TCNTL(0);
+#endif
+
+}
index 7775828..4391d03 100644 (file)
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 #include <linux/fs.h>
+#include <linux/delay.h>
 #include <asm/blackfin.h>
 #include <asm/time.h>
 #include <asm/dpmc.h>
 
+#define CPUFREQ_CPU 0
+
 /* this is the table of CCLK frequencies, in Hz */
 /* .index is the entry in the auxillary dpm_state_table[] */
 static struct cpufreq_frequency_table bfin_freq_table[] = {
@@ -41,64 +44,124 @@ static struct bfin_dpm_state {
        unsigned int tscale; /* change the divider on the core timer interrupt */
 } dpm_state_table[3];
 
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
 /*
  normalized to maximum frequncy offset for CYCLES,
  used in time-ts cycles clock source, but could be used
  somewhere also.
* normalized to maximum frequncy offset for CYCLES,
* used in time-ts cycles clock source, but could be used
* somewhere also.
  */
 unsigned long long __bfin_cycles_off;
 unsigned int __bfin_cycles_mod;
+#endif
 
 /**************************************************************************/
+static void __init bfin_init_tables(unsigned long cclk, unsigned long sclk)
+{
 
-static unsigned int bfin_getfreq_khz(unsigned int cpu)
+       unsigned long csel, min_cclk;
+       int index;
+
+       /* Anomaly 273 seems to still exist on non-BF54x w/dcache turned on */
+#if ANOMALY_05000273 || ANOMALY_05000274 || \
+       (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE))
+       min_cclk = sclk * 2;
+#else
+       min_cclk = sclk;
+#endif
+       csel = ((bfin_read_PLL_DIV() & CSEL) >> 4);
+
+       for (index = 0;  (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) {
+               bfin_freq_table[index].frequency = cclk >> index;
+               dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
+               dpm_state_table[index].tscale =  (TIME_SCALE / (1 << csel)) - 1;
+
+               pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n",
+                                                bfin_freq_table[index].frequency,
+                                                dpm_state_table[index].csel,
+                                                dpm_state_table[index].tscale);
+       }
+       return;
+}
+
+static void bfin_adjust_core_timer(void *info)
 {
-       /* The driver only support single cpu */
-       if (cpu != 0)
-               return -1;
+       unsigned int tscale;
+       unsigned int index = *(unsigned int *)info;
 
-       return get_cclk() / 1000;
+       /* we have to adjust the core timer, because it is using cclk */
+       tscale = dpm_state_table[index].tscale;
+       bfin_write_TSCALE(tscale);
+       return;
 }
 
+static unsigned int bfin_getfreq_khz(unsigned int cpu)
+{
+       /* Both CoreA/B have the same core clock */
+       return get_cclk() / 1000;
+}
 
-static int bfin_target(struct cpufreq_policy *policy,
+static int bfin_target(struct cpufreq_policy *poli,
                        unsigned int target_freq, unsigned int relation)
 {
-       unsigned int index, plldiv, tscale;
+       unsigned int index, plldiv, cpu;
        unsigned long flags, cclk_hz;
        struct cpufreq_freqs freqs;
+       static unsigned long lpj_ref;
+       static unsigned int  lpj_ref_freq;
+
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
        cycles_t cycles;
+#endif
 
-       if (cpufreq_frequency_table_target(policy, bfin_freq_table,
-                target_freq, relation, &index))
-               return -EINVAL;
-
-       cclk_hz = bfin_freq_table[index].frequency;
-
-       freqs.old = bfin_getfreq_khz(0);
-       freqs.new = cclk_hz;
-       freqs.cpu = 0;
-
-       pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
-                cclk_hz, target_freq, freqs.old);
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       local_irq_save_hw(flags);
-               plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
-               tscale = dpm_state_table[index].tscale;
-               bfin_write_PLL_DIV(plldiv);
-               /* we have to adjust the core timer, because it is using cclk */
-               bfin_write_TSCALE(tscale);
-               cycles = get_cycles();
-               SSYNC();
-       cycles += 10; /* ~10 cycles we lose after get_cycles() */
-       __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
-       __bfin_cycles_mod = index;
-       local_irq_restore_hw(flags);
-       /* TODO: just test case for cycles clock source, remove later */
-       pr_debug("cpufreq: done\n");
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       for_each_online_cpu(cpu) {
+               struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+
+               if (!policy)
+                       continue;
+
+               if (cpufreq_frequency_table_target(policy, bfin_freq_table,
+                                target_freq, relation, &index))
+                       return -EINVAL;
+
+               cclk_hz = bfin_freq_table[index].frequency;
+
+               freqs.old = bfin_getfreq_khz(0);
+               freqs.new = cclk_hz;
+               freqs.cpu = cpu;
+
+               pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
+                        cclk_hz, target_freq, freqs.old);
+
+               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+               if (cpu == CPUFREQ_CPU) {
+                       local_irq_save_hw(flags);
+                       plldiv = (bfin_read_PLL_DIV() & SSEL) |
+                                               dpm_state_table[index].csel;
+                       bfin_write_PLL_DIV(plldiv);
+                       on_each_cpu(bfin_adjust_core_timer, &index, 1);
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
+                       cycles = get_cycles();
+                       SSYNC();
+                       cycles += 10; /* ~10 cycles we lose after get_cycles() */
+                       __bfin_cycles_off +=
+                           (cycles << __bfin_cycles_mod) - (cycles << index);
+                       __bfin_cycles_mod = index;
+#endif
+                       if (!lpj_ref_freq) {
+                               lpj_ref = loops_per_jiffy;
+                               lpj_ref_freq = freqs.old;
+                       }
+                       if (freqs.new != freqs.old) {
+                               loops_per_jiffy = cpufreq_scale(lpj_ref,
+                                               lpj_ref_freq, freqs.new);
+                       }
+                       local_irq_restore_hw(flags);
+               }
+               /* TODO: just test case for cycles clock source, remove later */
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       }
 
+       pr_debug("cpufreq: done\n");
        return 0;
 }
 
@@ -110,37 +173,16 @@ static int bfin_verify_speed(struct cpufreq_policy *policy)
 static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
 {
 
-       unsigned long cclk, sclk, csel, min_cclk;
-       int index;
-
-       if (policy->cpu != 0)
-               return -EINVAL;
+       unsigned long cclk, sclk;
 
        cclk = get_cclk() / 1000;
        sclk = get_sclk() / 1000;
 
-#if ANOMALY_05000273 || ANOMALY_05000274 || \
-       (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE))
-       min_cclk = sclk * 2;
-#else
-       min_cclk = sclk;
-#endif
-       csel = ((bfin_read_PLL_DIV() & CSEL) >> 4);
-
-       for (index = 0;  (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) {
-               bfin_freq_table[index].frequency = cclk >> index;
-               dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
-               dpm_state_table[index].tscale =  (TIME_SCALE / (1 << csel)) - 1;
-
-               pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n",
-                                                bfin_freq_table[index].frequency,
-                                                dpm_state_table[index].csel,
-                                                dpm_state_table[index].tscale);
-       }
+       if (policy->cpu == CPUFREQ_CPU)
+               bfin_init_tables(cclk, sclk);
 
        policy->cpuinfo.transition_latency = 50000; /* 50us assumed */
 
-       /*Now ,only support one cpu */
        policy->cur = cclk;
        cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu);
        return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table);
index 01b2f58..a5847f5 100644 (file)
@@ -405,7 +405,7 @@ ENTRY(_double_fault)
 
        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
        SP += -12;
-       call _double_fault_c;
+       pseudo_long_call _double_fault_c, p5;
        SP += 12;
 .L_double_fault_panic:
         JUMP .L_double_fault_panic
@@ -447,7 +447,7 @@ ENTRY(_exception_to_level5)
 
        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
        SP += -12;
-       call _trap_c;
+       pseudo_long_call _trap_c, p4;
        SP += 12;
 
        /* If interrupts were off during the exception (IPEND[4] = 1), turn them off
@@ -482,6 +482,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
        [--sp] = ASTAT;
        [--sp] = (R7:6,P5:4);
 
+       ANOMALY_283_315_WORKAROUND(p5, r7)
+
 #ifdef CONFIG_EXACT_HWERR
        /* Make sure all pending read/writes complete. This will ensure any
         * accesses which could cause hardware errors completes, and signal
@@ -492,8 +494,6 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
        ssync;
 #endif
 
-       ANOMALY_283_315_WORKAROUND(p5, r7)
-
 #ifdef CONFIG_DEBUG_DOUBLEFAULT
        /*
         * Save these registers, as they are only valid in exception context
@@ -551,7 +551,7 @@ ENTRY(_kernel_execve)
        p0 = sp;
        sp += -16;
        [sp + 12] = p0;
-       call _do_execve;
+       pseudo_long_call _do_execve, p5;
        SP += 16;
        cc = r0 == 0;
        if ! cc jump .Lexecve_failed;
@@ -626,13 +626,6 @@ ENTRY(_system_call)
        p0 = [sp + PT_ORIG_P0];
 #endif /* CONFIG_IPIPE */
 
-       /* Check the System Call */
-       r7 = __NR_syscall;
-       /* System call number is passed in P0 */
-       r6 = p0;
-       cc = r6 < r7;
-       if ! cc jump .Lbadsys;
-
        /* are we tracing syscalls?*/
        r7 = sp;
        r6.l = lo(ALIGN_PAGE_MASK);
@@ -642,6 +635,14 @@ ENTRY(_system_call)
        r7 = [p2+TI_FLAGS];
        CC = BITTST(r7,TIF_SYSCALL_TRACE);
        if CC JUMP _sys_trace;
+       CC = BITTST(r7,TIF_SINGLESTEP);
+       if CC JUMP _sys_trace;
+
+       /* Make sure the system call # is valid */
+       p4 = __NR_syscall;
+       /* System call number is passed in P0 */
+       cc = p4 <= p0;
+       if cc jump .Lbadsys;
 
        /* Execute the appropriate system call */
 
@@ -704,7 +705,7 @@ ENTRY(_system_call)
        sp += 4;
 
        SP += -12;
-       call _schedule;
+       pseudo_long_call _schedule, p4;
        SP += 12;
 
        jump .Lresume_userspace_1;
@@ -723,7 +724,7 @@ ENTRY(_system_call)
 
        r0 = sp;
        SP += -12;
-       call _do_notify_resume;
+       pseudo_long_call _do_notify_resume, p5;
        SP += 12;
 
 .Lsyscall_really_exit:
@@ -736,11 +737,17 @@ ENDPROC(_system_call)
  * this symbol need not be global anyways, so ...
  */
 _sys_trace:
-       call _syscall_trace;
-
-       /* Execute the appropriate system call */
+       r0 = sp;
+       pseudo_long_call _syscall_trace_enter, p5;
 
+       /* Make sure the system call # is valid */
        p4 = [SP + PT_P0];
+       p3 = __NR_syscall;
+       cc = p3 <= p4;
+       r0 = -ENOSYS;
+       if cc jump .Lsys_trace_badsys;
+
+       /* Execute the appropriate system call */
        p5.l = _sys_call_table;
        p5.h = _sys_call_table;
        p5 = p5 + (p4 << 2);
@@ -758,9 +765,11 @@ _sys_trace:
        SP += -12;
        call (p5);
        SP += 24;
+.Lsys_trace_badsys:
        [sp + PT_R0] = r0;
 
-       call _syscall_trace;
+       r0 = sp;
+       pseudo_long_call _syscall_trace_leave, p5;
        jump .Lresume_userspace;
 ENDPROC(_sys_trace)
 
@@ -966,6 +975,13 @@ ENTRY(_evt_evt14)
 #else
        cli r0;
 #endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+       [--sp] = rets;
+       sp += -12;
+       call _trace_hardirqs_off;
+       sp += 12;
+       rets = [sp++];
+#endif
        [--sp] = RETI;
        SP += 4;
        rts;
@@ -989,6 +1005,14 @@ ENTRY(_schedule_and_signal_from_int)
        p1 = rets;
        [sp + PT_RESERVED] = p1;
 
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* trace_hardirqs_on() checks if all irqs are disabled. But here IRQ 15
+        * is turned on, so disable all irqs. */
+       cli r0;
+       sp += -12;
+       call _trace_hardirqs_on;
+       sp += 12;
+#endif
 #ifdef CONFIG_SMP
        GET_PDA(p0, r0);        /* Fetch current PDA (can't migrate to other CPU here) */
        r0 = [p0 + PDA_IRQFLAGS];
@@ -1007,7 +1031,8 @@ ENTRY(_schedule_and_signal_from_int)
 
        r0 = sp;
        sp += -12;
-       call _finish_atomic_sections;
+
+       pseudo_long_call _finish_atomic_sections, p5;
        sp += 12;
        jump.s .Lresume_userspace;
 ENDPROC(_schedule_and_signal_from_int)
@@ -1357,7 +1382,7 @@ ENTRY(_sys_call_table)
        .long _sys_newuname
        .long _sys_ni_syscall   /* old sys_modify_ldt */
        .long _sys_adjtimex
-       .long _sys_ni_syscall   /* 125 */ /* sys_mprotect */
+       .long _sys_mprotect     /* 125 */
        .long _sys_ni_syscall   /* old sys_sigprocmask */
        .long _sys_ni_syscall   /* old "creat_module" */
        .long _sys_init_module
@@ -1376,16 +1401,16 @@ ENTRY(_sys_call_table)
        .long _sys_getdents
        .long _sys_ni_syscall   /* sys_select */
        .long _sys_flock
-       .long _sys_ni_syscall   /* sys_msync */
+       .long _sys_msync
        .long _sys_readv                /* 145 */
        .long _sys_writev
        .long _sys_getsid
        .long _sys_fdatasync
        .long _sys_sysctl
-       .long _sys_ni_syscall   /* 150 */ /* sys_mlock */
-       .long _sys_ni_syscall   /* sys_munlock */
-       .long _sys_ni_syscall   /* sys_mlockall */
-       .long _sys_ni_syscall   /* sys_munlockall */
+       .long _sys_mlock        /* 150 */
+       .long _sys_munlock
+       .long _sys_mlockall
+       .long _sys_munlockall
        .long _sys_sched_setparam
        .long _sys_sched_getparam /* 155 */
        .long _sys_sched_setscheduler
@@ -1450,8 +1475,8 @@ ENTRY(_sys_call_table)
        .long _sys_setfsuid     /* 215 */
        .long _sys_setfsgid
        .long _sys_pivot_root
-       .long _sys_ni_syscall   /* sys_mincore */
-       .long _sys_ni_syscall   /* sys_madvise */
+       .long _sys_mincore
+       .long _sys_madvise
        .long _sys_getdents64   /* 220 */
        .long _sys_fcntl64
        .long _sys_ni_syscall   /* reserved for TUX */
@@ -1507,7 +1532,7 @@ ENTRY(_sys_call_table)
        .long _sys_utimes
        .long _sys_fadvise64_64
        .long _sys_ni_syscall /* vserver */
-       .long _sys_ni_syscall /* 275, mbind */
+       .long _sys_mbind        /* 275 */
        .long _sys_ni_syscall /* get_mempolicy */
        .long _sys_ni_syscall /* set_mempolicy */
        .long _sys_mq_open
index cab0a00..4391621 100644 (file)
@@ -144,8 +144,8 @@ ENTRY(__start)
 #endif
 
        /* Initialize stack pointer */
-       sp.l = _init_thread_union;
-       sp.h = _init_thread_union;
+       sp.l = _init_thread_union + THREAD_SIZE;
+       sp.h = _init_thread_union + THREAD_SIZE;
        fp = sp;
        usp = sp;
 
@@ -186,6 +186,11 @@ ENTRY(__start)
 
        /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
        call _bfin_relocate_l1_mem;
+
+#ifdef CONFIG_ROMKERNEL
+       call _bfin_relocate_xip_data;
+#endif
+
 #ifdef CONFIG_BFIN_KERNEL_CLOCK
        /* Only use on-chip scratch space for stack when absolutely required
         * to avoid Anomaly 05000227 ... we know the init_clocks() func only
@@ -257,12 +262,7 @@ ENTRY(_real_start)
        R0 = R7;
        call _cmdline_init;
 
-       /* Load the current thread pointer and stack */
-       p1 = THREAD_SIZE + 4 (z);       /* +4 is for reti loading */
-       sp = sp + p1;
-       usp = sp;
-       fp = sp;
-       sp += -12;
+       sp += -12 + 4; /* +4 is for reti loading above */
        call _init_pda
        sp += 12;
        jump.l _start_kernel;
index 8085ff1..cee62cf 100644 (file)
@@ -88,6 +88,13 @@ __common_int_entry:
 #else
        cli r1;
 #endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+       [--sp] = r0;
+       sp += -12;
+       call _trace_hardirqs_off;
+       sp += 12;
+       r0 = [sp++];
+#endif
        [--sp] = RETI;  /* orig_pc */
        /* Clear all L registers.  */
        r1 = 0 (x);
@@ -109,10 +116,10 @@ __common_int_entry:
        cc = r0 == 0;
        if cc jump .Lcommon_restore_context;
 #else /* CONFIG_IPIPE */
-       call _do_irq;
+       pseudo_long_call _do_irq, p2;
        SP += 12;
 #endif /* CONFIG_IPIPE */
-       call _return_from_int;
+       pseudo_long_call _return_from_int, p2;
 .Lcommon_restore_context:
        RESTORE_CONTEXT
        rti;
@@ -168,7 +175,7 @@ ENTRY(_evt_ivhw)
 
        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
        SP += -12;
-       call _trap_c;
+       pseudo_long_call _trap_c, p5;
        SP += 12;
 
 #ifdef EBIU_ERRMST
@@ -179,7 +186,7 @@ ENTRY(_evt_ivhw)
        w[p0] = r0.l;
 #endif
 
-       call _ret_from_exception;
+       pseudo_long_call _ret_from_exception, p2;
 
 .Lcommon_restore_all_sys:
        RESTORE_ALL_SYS
@@ -187,12 +194,28 @@ ENTRY(_evt_ivhw)
 ENDPROC(_evt_ivhw)
 
 /* Interrupt routine for evt2 (NMI).
- * We don't actually use this, so just return.
  * For inner circle type details, please see:
  * http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:nmi
  */
 ENTRY(_evt_nmi)
+#ifndef CONFIG_NMI_WATCHDOG
 .weak _evt_nmi
+#else
+       /* Not take account of CPLBs, this handler will not return */
+       SAVE_ALL_SYS
+       r0 = sp;
+       r1 = retn;
+       [sp + PT_PC] = r1;
+       trace_buffer_save(p4,r5);
+
+       ANOMALY_283_315_WORKAROUND(p4, r5)
+
+       SP += -12;
+       call _do_nmi;
+       SP += 12;
+1:
+       jump 1b;
+#endif
        rtn;
 ENDPROC(_evt_nmi)
 
@@ -223,7 +246,7 @@ ENTRY(_evt_system_call)
 #ifdef CONFIG_FRAME_POINTER
        fp = 0;
 #endif
-       call _system_call;
+       pseudo_long_call _system_call, p2;
        jump .Lcommon_restore_context;
 ENDPROC(_evt_system_call)
 
index 1873b2c..7ad8878 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/dpmc.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/bfin_sport.h>
+#include <asm/bfin_can.h>
 
 #define SIC_SYSIRQ(irq)        (irq - (IRQ_CORETMR + 1))
 
@@ -172,7 +173,12 @@ static void bfin_internal_mask_irq(unsigned int irq)
        local_irq_restore_hw(flags);
 }
 
+#ifdef CONFIG_SMP
+static void bfin_internal_unmask_irq_affinity(unsigned int irq,
+               const struct cpumask *affinity)
+#else
 static void bfin_internal_unmask_irq(unsigned int irq)
+#endif
 {
        unsigned long flags;
 
@@ -185,16 +191,38 @@ static void bfin_internal_unmask_irq(unsigned int irq)
        local_irq_save_hw(flags);
        mask_bank = SIC_SYSIRQ(irq) / 32;
        mask_bit = SIC_SYSIRQ(irq) % 32;
-       bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
-                            (1 << mask_bit));
 #ifdef CONFIG_SMP
-       bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
-                            (1 << mask_bit));
+       if (cpumask_test_cpu(0, affinity))
+#endif
+               bfin_write_SIC_IMASK(mask_bank,
+                       bfin_read_SIC_IMASK(mask_bank) |
+                       (1 << mask_bit));
+#ifdef CONFIG_SMP
+       if (cpumask_test_cpu(1, affinity))
+               bfin_write_SICB_IMASK(mask_bank,
+                       bfin_read_SICB_IMASK(mask_bank) |
+                       (1 << mask_bit));
 #endif
 #endif
        local_irq_restore_hw(flags);
 }
 
+#ifdef CONFIG_SMP
+static void bfin_internal_unmask_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       bfin_internal_unmask_irq_affinity(irq, desc->affinity);
+}
+
+static int bfin_internal_set_affinity(unsigned int irq, const struct cpumask *mask)
+{
+       bfin_internal_mask_irq(irq);
+       bfin_internal_unmask_irq_affinity(irq, mask);
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_PM
 int bfin_internal_set_wake(unsigned int irq, unsigned int state)
 {
@@ -224,11 +252,6 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
        wakeup |= USBWE;
        break;
 #endif
-#ifdef IRQ_KEY
-       case IRQ_KEY:
-       wakeup |= KPADWE;
-       break;
-#endif
 #ifdef CONFIG_BF54x
        case IRQ_CNT:
        wakeup |= ROTWE;
@@ -270,6 +293,9 @@ static struct irq_chip bfin_internal_irqchip = {
        .mask_ack = bfin_internal_mask_irq,
        .disable = bfin_internal_mask_irq,
        .enable = bfin_internal_unmask_irq,
+#ifdef CONFIG_SMP
+       .set_affinity = bfin_internal_set_affinity,
+#endif
 #ifdef CONFIG_PM
        .set_wake = bfin_internal_set_wake,
 #endif
@@ -294,7 +320,6 @@ static int error_int_mask;
 static void bfin_generic_error_mask_irq(unsigned int irq)
 {
        error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
-
        if (!error_int_mask)
                bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
 }
@@ -385,6 +410,127 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
 }
 #endif                         /* BF537_GENERIC_ERROR_INT_DEMUX */
 
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static int mac_stat_int_mask;
+
+static void bfin_mac_status_ack_irq(unsigned int irq)
+{
+       switch (irq) {
+       case IRQ_MAC_MMCINT:
+               bfin_write_EMAC_MMC_TIRQS(
+                       bfin_read_EMAC_MMC_TIRQE() &
+                       bfin_read_EMAC_MMC_TIRQS());
+               bfin_write_EMAC_MMC_RIRQS(
+                       bfin_read_EMAC_MMC_RIRQE() &
+                       bfin_read_EMAC_MMC_RIRQS());
+               break;
+       case IRQ_MAC_RXFSINT:
+               bfin_write_EMAC_RX_STKY(
+                       bfin_read_EMAC_RX_IRQE() &
+                       bfin_read_EMAC_RX_STKY());
+               break;
+       case IRQ_MAC_TXFSINT:
+               bfin_write_EMAC_TX_STKY(
+                       bfin_read_EMAC_TX_IRQE() &
+                       bfin_read_EMAC_TX_STKY());
+               break;
+       case IRQ_MAC_WAKEDET:
+                bfin_write_EMAC_WKUP_CTL(
+                       bfin_read_EMAC_WKUP_CTL() | MPKS | RWKS);
+               break;
+       default:
+               /* These bits are W1C */
+               bfin_write_EMAC_SYSTAT(1L << (irq - IRQ_MAC_PHYINT));
+               break;
+       }
+}
+
+static void bfin_mac_status_mask_irq(unsigned int irq)
+{
+       mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+       switch (irq) {
+       case IRQ_MAC_PHYINT:
+               bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE);
+               break;
+       default:
+               break;
+       }
+#else
+       if (!mac_stat_int_mask)
+               bfin_internal_mask_irq(IRQ_MAC_ERROR);
+#endif
+       bfin_mac_status_ack_irq(irq);
+}
+
+static void bfin_mac_status_unmask_irq(unsigned int irq)
+{
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+       switch (irq) {
+       case IRQ_MAC_PHYINT:
+               bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE);
+               break;
+       default:
+               break;
+       }
+#else
+       if (!mac_stat_int_mask)
+               bfin_internal_unmask_irq(IRQ_MAC_ERROR);
+#endif
+       mac_stat_int_mask |= 1L << (irq - IRQ_MAC_PHYINT);
+}
+
+#ifdef CONFIG_PM
+int bfin_mac_status_set_wake(unsigned int irq, unsigned int state)
+{
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+       return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
+#else
+       return bfin_internal_set_wake(IRQ_MAC_ERROR, state);
+#endif
+}
+#endif
+
+static struct irq_chip bfin_mac_status_irqchip = {
+       .name = "MACST",
+       .ack = bfin_ack_noop,
+       .mask_ack = bfin_mac_status_mask_irq,
+       .mask = bfin_mac_status_mask_irq,
+       .unmask = bfin_mac_status_unmask_irq,
+#ifdef CONFIG_PM
+       .set_wake = bfin_mac_status_set_wake,
+#endif
+};
+
+static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
+                                struct irq_desc *inta_desc)
+{
+       int i, irq = 0;
+       u32 status = bfin_read_EMAC_SYSTAT();
+
+       for (i = 0; i < (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++)
+               if (status & (1L << i)) {
+                       irq = IRQ_MAC_PHYINT + i;
+                       break;
+               }
+
+       if (irq) {
+               if (mac_stat_int_mask & (1L << (irq - IRQ_MAC_PHYINT))) {
+                       bfin_handle_irq(irq);
+               } else {
+                       bfin_mac_status_ack_irq(irq);
+                       pr_debug("IRQ %d:"
+                                " MASKED MAC ERROR INTERRUPT ASSERTED\n",
+                                irq);
+               }
+       } else
+               printk(KERN_ERR
+                      "%s : %s : LINE %d :\nIRQ ?: MAC ERROR"
+                      " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+                      __func__, __FILE__, __LINE__);
+}
+#endif
+
 static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
 {
 #ifdef CONFIG_IPIPE
@@ -1031,7 +1177,6 @@ int __init init_arch_irq(void)
 #elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
                case IRQ_PORTF_INTA:
 #endif
-
                        set_irq_chained_handler(irq,
                                                bfin_demux_gpio_irq);
                        break;
@@ -1040,29 +1185,36 @@ int __init init_arch_irq(void)
                        set_irq_chained_handler(irq, bfin_demux_error_irq);
                        break;
 #endif
-
-#ifdef CONFIG_SMP
-#ifdef CONFIG_TICKSOURCE_GPTMR0
-               case IRQ_TIMER0:
-#endif
-#ifdef CONFIG_TICKSOURCE_CORETMR
-               case IRQ_CORETMR:
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+               case IRQ_MAC_ERROR:
+                       set_irq_chained_handler(irq, bfin_demux_mac_status_irq);
+                       break;
 #endif
+#ifdef CONFIG_SMP
                case IRQ_SUPPLE_0:
                case IRQ_SUPPLE_1:
                        set_irq_handler(irq, handle_percpu_irq);
                        break;
 #endif
 
-#ifdef CONFIG_IPIPE
-#ifndef CONFIG_TICKSOURCE_CORETMR
-               case IRQ_TIMER0:
+#ifdef CONFIG_TICKSOURCE_CORETMR
+               case IRQ_CORETMR:
+# ifdef CONFIG_SMP
+                       set_irq_handler(irq, handle_percpu_irq);
+                       break;
+# else
                        set_irq_handler(irq, handle_simple_irq);
                        break;
+# endif
 #endif
-               case IRQ_CORETMR:
+
+#ifdef CONFIG_TICKSOURCE_GPTMR0
+               case IRQ_TIMER0:
                        set_irq_handler(irq, handle_simple_irq);
                        break;
+#endif
+
+#ifdef CONFIG_IPIPE
                default:
                        set_irq_handler(irq, handle_level_irq);
                        break;
@@ -1078,14 +1230,22 @@ int __init init_arch_irq(void)
        for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
                set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
                                         handle_level_irq);
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       set_irq_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
+#endif
 #endif
 
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++)
+               set_irq_chip_and_handler(irq, &bfin_mac_status_irqchip,
+                                        handle_level_irq);
+#endif
        /* if configured as edge, then will be changed to do_edge_IRQ */
-       for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
+       for (irq = GPIO_IRQ_BASE;
+               irq < (GPIO_IRQ_BASE + MAX_BLACKFIN_GPIOS); irq++)
                set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
                                         handle_level_irq);
 
-
        bfin_write_IMASK(0);
        CSYNC();
        ilat = bfin_read_ILAT();
index 369e687..7803f22 100644 (file)
@@ -122,9 +122,17 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
        wait = msg->call_struct.wait;
        cpu_clear(cpu, msg->call_struct.pending);
        func(info);
-       if (wait)
+       if (wait) {
+#ifdef __ARCH_SYNC_CORE_DCACHE
+               /*
+                * 'wait' usually means synchronization between CPUs.
+                * Invalidate D cache in case shared data was changed
+                * by func() to ensure cache coherence.
+                */
+               resync_core_dcache();
+#endif
                cpu_clear(cpu, msg->call_struct.waitmask);
-       else
+       else
                kfree(msg);
 }
 
@@ -219,6 +227,13 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
                        blackfin_dcache_invalidate_range(
                                (unsigned long)(&msg->call_struct.waitmask),
                                (unsigned long)(&msg->call_struct.waitmask));
+#ifdef __ARCH_SYNC_CORE_DCACHE
+               /*
+                * Invalidate D cache in case shared data was changed by
+                * other processors to ensure cache coherence.
+                */
+               resync_core_dcache();
+#endif
                kfree(msg);
        }
        return 0;
@@ -261,6 +276,13 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
                        blackfin_dcache_invalidate_range(
                                (unsigned long)(&msg->call_struct.waitmask),
                                (unsigned long)(&msg->call_struct.waitmask));
+#ifdef __ARCH_SYNC_CORE_DCACHE
+               /*
+                * Invalidate D cache in case shared data was changed by
+                * other processors to ensure cache coherence.
+                */
+               resync_core_dcache();
+#endif
                kfree(msg);
        }
        return 0;
@@ -322,8 +344,11 @@ void smp_send_stop(void)
 
 int __cpuinit __cpu_up(unsigned int cpu)
 {
-       struct task_struct *idle;
        int ret;
+       static struct task_struct *idle;
+
+       if (idle)
+               free_task(idle);
 
        idle = fork_idle(cpu);
        if (IS_ERR(idle)) {
@@ -332,7 +357,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
        }
 
        secondary_stack = task_stack_page(idle) + THREAD_SIZE;
-       smp_wmb();
 
        ret = platform_boot_secondary(cpu, idle);
 
@@ -343,9 +367,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
 static void __cpuinit setup_secondary(unsigned int cpu)
 {
-#if !defined(CONFIG_TICKSOURCE_GPTMR0)
-       struct irq_desc *timer_desc;
-#endif
        unsigned long ilat;
 
        bfin_write_IMASK(0);
@@ -360,17 +381,6 @@ static void __cpuinit setup_secondary(unsigned int cpu)
        bfin_irq_flags |= IMASK_IVG15 |
            IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
            IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
-
-#if defined(CONFIG_TICKSOURCE_GPTMR0)
-       /* Power down the core timer, just to play safe. */
-       bfin_write_TCNTL(0);
-
-       /* system timer0 has been setup by CoreA. */
-#else
-       timer_desc = irq_desc + IRQ_CORETMR;
-       setup_core_timer();
-       timer_desc->chip->enable(IRQ_CORETMR);
-#endif
 }
 
 void __cpuinit secondary_start_kernel(void)
@@ -405,7 +415,6 @@ void __cpuinit secondary_start_kernel(void)
        atomic_inc(&mm->mm_users);
        atomic_inc(&mm->mm_count);
        current->active_mm = mm;
-       BUG_ON(current->mm);    /* Can't be, but better be safe than sorry. */
 
        preempt_disable();
 
@@ -413,6 +422,9 @@ void __cpuinit secondary_start_kernel(void)
 
        platform_secondary_init(cpu);
 
+       /* setup local core timer */
+       bfin_local_timer_setup();
+
        local_irq_enable();
 
        /*
@@ -462,25 +474,58 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end)
 EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
 
 #ifdef __ARCH_SYNC_CORE_ICACHE
+unsigned long icache_invld_count[NR_CPUS];
 void resync_core_icache(void)
 {
        unsigned int cpu = get_cpu();
        blackfin_invalidate_entire_icache();
-       ++per_cpu(cpu_data, cpu).icache_invld_count;
+       icache_invld_count[cpu]++;
        put_cpu();
 }
 EXPORT_SYMBOL(resync_core_icache);
 #endif
 
 #ifdef __ARCH_SYNC_CORE_DCACHE
+unsigned long dcache_invld_count[NR_CPUS];
 unsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
 
 void resync_core_dcache(void)
 {
        unsigned int cpu = get_cpu();
        blackfin_invalidate_entire_dcache();
-       ++per_cpu(cpu_data, cpu).dcache_invld_count;
+       dcache_invld_count[cpu]++;
        put_cpu();
 }
 EXPORT_SYMBOL(resync_core_dcache);
 #endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+int __cpuexit __cpu_disable(void)
+{
+       unsigned int cpu = smp_processor_id();
+
+       if (cpu == 0)
+               return -EPERM;
+
+       set_cpu_online(cpu, false);
+       return 0;
+}
+
+static DECLARE_COMPLETION(cpu_killed);
+
+int __cpuexit __cpu_die(unsigned int cpu)
+{
+       return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+void cpu_die(void)
+{
+       complete(&cpu_killed);
+
+       atomic_dec(&init_mm.mm_users);
+       atomic_dec(&init_mm.mm_count);
+
+       local_irq_disable();
+       platform_cpu_die();
+}
+#endif
index 84cdc5a..9213e23 100644 (file)
@@ -62,7 +62,7 @@ static void isram_write(const void *addr, uint64_t data)
        uint32_t cmd;
        unsigned long flags;
 
-       if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH))
+       if (unlikely(addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH)))
                return;
 
        cmd = IADDR2DTEST(addr) | 2;             /* write */
@@ -93,7 +93,7 @@ static uint64_t isram_read(const void *addr)
        unsigned long flags;
        uint64_t ret;
 
-       if (addr > (void *)(L1_CODE_START + L1_CODE_LENGTH))
+       if (unlikely(addr > (void *)(L1_CODE_START + L1_CODE_LENGTH)))
                return 0;
 
        cmd = IADDR2DTEST(addr) | 0;              /* read */
@@ -120,7 +120,7 @@ static bool isram_check_addr(const void *addr, size_t n)
 {
        if ((addr >= (void *)L1_CODE_START) &&
            (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
-               if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+               if (unlikely((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
                        show_stack(NULL, NULL);
                        pr_err("copy involving %p length (%zu) too long\n", addr, n);
                }
index f068c11..5732da2 100644 (file)
@@ -402,7 +402,7 @@ void *l1_data_A_sram_alloc(size_t size)
        void *addr;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
 
@@ -411,7 +411,6 @@ void *l1_data_A_sram_alloc(size_t size)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
-       put_cpu();
 
        pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
                 (long unsigned int)addr, size);
@@ -430,7 +429,7 @@ int l1_data_A_sram_free(const void *addr)
        int ret;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
 
@@ -439,7 +438,6 @@ int l1_data_A_sram_free(const void *addr)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
-       put_cpu();
 
        return ret;
 #else
@@ -455,7 +453,7 @@ void *l1_data_B_sram_alloc(size_t size)
        void *addr;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
 
@@ -464,7 +462,6 @@ void *l1_data_B_sram_alloc(size_t size)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
-       put_cpu();
 
        pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
                 (long unsigned int)addr, size);
@@ -483,7 +480,7 @@ int l1_data_B_sram_free(const void *addr)
        int ret;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
 
@@ -492,7 +489,6 @@ int l1_data_B_sram_free(const void *addr)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
-       put_cpu();
 
        return ret;
 #else
@@ -540,7 +536,7 @@ void *l1_inst_sram_alloc(size_t size)
        void *addr;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
 
@@ -549,7 +545,6 @@ void *l1_inst_sram_alloc(size_t size)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
-       put_cpu();
 
        pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
                 (long unsigned int)addr, size);
@@ -568,7 +563,7 @@ int l1_inst_sram_free(const void *addr)
        int ret;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
 
@@ -577,7 +572,6 @@ int l1_inst_sram_free(const void *addr)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
-       put_cpu();
 
        return ret;
 #else
@@ -593,7 +587,7 @@ void *l1sram_alloc(size_t size)
        void *addr;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
 
@@ -602,7 +596,6 @@ void *l1sram_alloc(size_t size)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
-       put_cpu();
 
        return addr;
 }
@@ -614,7 +607,7 @@ void *l1sram_alloc_max(size_t *psize)
        void *addr;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
 
@@ -623,7 +616,6 @@ void *l1sram_alloc_max(size_t *psize)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
-       put_cpu();
 
        return addr;
 }
@@ -635,7 +627,7 @@ int l1sram_free(const void *addr)
        int ret;
        unsigned int cpu;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
        /* add mutex operation */
        spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
 
@@ -644,7 +636,6 @@ int l1sram_free(const void *addr)
 
        /* add mutex operation */
        spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
-       put_cpu();
 
        return ret;
 }
index b008168..203ec61 100644 (file)
@@ -14,6 +14,8 @@ config MICROBLAZE
        select USB_ARCH_HAS_EHCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_OPROFILE
+       select HAVE_DMA_ATTRS
+       select HAVE_DMA_API_DEBUG
        select TRACING_SUPPORT
 
 config SWAP
@@ -76,9 +78,6 @@ config HAVE_LATENCYTOP_SUPPORT
 config PCI
        def_bool n
 
-config NO_DMA
-       def_bool y
-
 config DTC
        def_bool y
 
@@ -146,7 +145,6 @@ menu "Advanced setup"
 
 config ADVANCED_OPTIONS
        bool "Prompt for advanced kernel configuration options"
-       depends on MMU
        help
          This option will enable prompting for a variety of advanced kernel
          configuration options.  These options can cause the kernel to not
@@ -158,6 +156,15 @@ config ADVANCED_OPTIONS
 comment "Default settings for advanced configuration options are used"
        depends on !ADVANCED_OPTIONS
 
+config XILINX_UNCACHED_SHADOW
+       bool "Are you using uncached shadow for RAM ?"
+       depends on ADVANCED_OPTIONS && !MMU
+       default n
+       help
+         This is needed to be able to allocate uncachable memory regions.
+         The feature requires the design to define the RAM memory controller
+         window to be twice as large as the actual physical memory.
+
 config HIGHMEM_START_BOOL
        bool "Set high memory pool address"
        depends on ADVANCED_OPTIONS && HIGHMEM
@@ -175,7 +182,7 @@ config HIGHMEM_START
 
 config LOWMEM_SIZE_BOOL
        bool "Set maximum low memory"
-       depends on ADVANCED_OPTIONS
+       depends on ADVANCED_OPTIONS && MMU
        help
          This option allows you to set the maximum amount of memory which
          will be used as "low memory", that is, memory which the kernel can
@@ -187,7 +194,6 @@ config LOWMEM_SIZE_BOOL
 
 config LOWMEM_SIZE
        hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
-       depends on MMU
        default "0x30000000"
 
 config KERNEL_START_BOOL
@@ -208,7 +214,7 @@ config KERNEL_START
 
 config TASK_SIZE_BOOL
        bool "Set custom user task size"
-       depends on ADVANCED_OPTIONS
+       depends on ADVANCED_OPTIONS && MMU
        help
          This option allows you to set the amount of virtual address space
          allocated to user tasks.  This can be useful in optimizing the
@@ -218,42 +224,34 @@ config TASK_SIZE_BOOL
 
 config TASK_SIZE
        hex "Size of user task space" if TASK_SIZE_BOOL
-       depends on MMU
        default "0x80000000"
 
-config CONSISTENT_START_BOOL
-       bool "Set custom consistent memory pool address"
-       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
-       help
-         This option allows you to set the base virtual address
-         of the the consistent memory pool.  This pool of virtual
-         memory is used to make consistent memory allocations.
+endmenu
 
-config CONSISTENT_START
-       hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL
-       depends on MMU
-       default "0xff100000" if NOT_COHERENT_CACHE
+source "mm/Kconfig"
 
-config CONSISTENT_SIZE_BOOL
-       bool "Set custom consistent memory pool size"
-       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
-       help
-         This option allows you to set the size of the the
-         consistent memory pool.  This pool of virtual memory
-         is used to make consistent memory allocations.
+menu "Exectuable file formats"
 
-config CONSISTENT_SIZE
-       hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL
-       depends on MMU
-       default "0x00200000" if NOT_COHERENT_CACHE
+source "fs/Kconfig.binfmt"
 
 endmenu
 
-source "mm/Kconfig"
+menu "Bus Options"
 
-menu "Exectuable file formats"
+config PCI
+       bool "PCI support"
 
-source "fs/Kconfig.binfmt"
+config PCI_DOMAINS
+       def_bool PCI
+
+config PCI_SYSCALL
+       def_bool PCI
+
+config PCI_XILINX
+       bool "Xilinx PCI host bridge support"
+       depends on PCI
+
+source "drivers/pci/Kconfig"
 
 endmenu
 
index d2d6cfc..836832d 100644 (file)
@@ -50,6 +50,7 @@ libs-y += $(LIBGCC)
 core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
+core-$(CONFIG_PCI) += arch/microblaze/pci/
 
 drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
 
index 78a0384..402b46e 100644 (file)
@@ -14,6 +14,10 @@ struct device_node;
 struct dev_archdata {
        /* Optional pointer to an OF device node */
        struct device_node      *of_node;
+
+       /* DMA operations on that device */
+       struct dma_map_ops      *dma_ops;
+       void                    *dma_data;
 };
 
 struct pdev_archdata {
index d00e400..18b3731 100644 (file)
@@ -1 +1,153 @@
-#include <asm-generic/dma-mapping-broken.h>
+/*
+ * Implements the generic device dma API for microblaze and the pci
+ *
+ * Copyright (C) 2009-2010 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009-2010 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * This file is base on powerpc and x86 dma-mapping.h versions
+ * Copyright (C) 2004 IBM
+ */
+
+#ifndef _ASM_MICROBLAZE_DMA_MAPPING_H
+#define _ASM_MICROBLAZE_DMA_MAPPING_H
+
+/*
+ * See Documentation/PCI/PCI-DMA-mapping.txt and
+ * Documentation/DMA-API.txt for documentation.
+ */
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/dma-attrs.h>
+#include <asm/io.h>
+#include <asm-generic/dma-coherent.h>
+
+#define DMA_ERROR_CODE         (~(dma_addr_t)0x0)
+
+#define __dma_alloc_coherent(dev, gfp, size, handle)   NULL
+#define __dma_free_coherent(size, addr)                ((void)0)
+#define __dma_sync(addr, size, rw)             ((void)0)
+
+static inline unsigned long device_to_mask(struct device *dev)
+{
+       if (dev->dma_mask && *dev->dma_mask)
+               return *dev->dma_mask;
+       /* Assume devices without mask can take 32 bit addresses */
+       return 0xfffffffful;
+}
+
+extern struct dma_map_ops *dma_ops;
+
+/*
+ * Available generic sets of operations
+ */
+extern struct dma_map_ops dma_direct_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+       /* We don't handle the NULL dev case for ISA for now. We could
+        * do it via an out of line call but it is not needed for now. The
+        * only ISA DMA device we support is the floppy and we have a hack
+        * in the floppy driver directly to get a device for us.
+        */
+       if (unlikely(!dev) || !dev->archdata.dma_ops)
+               return NULL;
+
+       return dev->archdata.dma_ops;
+}
+
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+       dev->archdata.dma_ops = ops;
+}
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+
+       if (unlikely(!ops))
+               return 0;
+       if (!ops->dma_supported)
+               return 1;
+       return ops->dma_supported(dev, mask);
+}
+
+#ifdef CONFIG_PCI
+/* We have our own implementation of pci_set_dma_mask() */
+#define HAVE_ARCH_PCI_SET_DMA_MASK
+
+#endif
+
+static inline int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+
+       if (unlikely(ops == NULL))
+               return -EIO;
+       if (ops->set_dma_mask)
+               return ops->set_dma_mask(dev, dma_mask);
+       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+               return -EIO;
+       *dev->dma_mask = dma_mask;
+       return 0;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+       if (ops->mapping_error)
+               return ops->mapping_error(dev, dma_addr);
+
+       return (dma_addr == DMA_ERROR_CODE);
+}
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d, h)        (1)
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                       dma_addr_t *dma_handle, gfp_t flag)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+       void *memory;
+
+       BUG_ON(!ops);
+
+       memory = ops->alloc_coherent(dev, size, dma_handle, flag);
+
+       debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
+       return memory;
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_handle)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+
+       BUG_ON(!ops);
+       debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+       ops->free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+       return L1_CACHE_BYTES;
+}
+
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+               enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+       __dma_sync(vaddr, size, (int)direction);
+}
+
+#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
index 267c7c7..32d621a 100644 (file)
 #include <asm/page.h>
 #include <linux/types.h>
 #include <linux/mm.h>          /* Get struct page {...} */
+#include <asm-generic/iomap.h>
 
+#ifndef CONFIG_PCI
+#define _IO_BASE       0
+#define _ISA_MEM_BASE  0
+#define PCI_DRAM_OFFSET        0
+#else
+#define _IO_BASE       isa_io_base
+#define _ISA_MEM_BASE  isa_mem_base
+#define PCI_DRAM_OFFSET        pci_dram_offset
+#endif
+
+extern unsigned long isa_io_base;
+extern unsigned long pci_io_base;
+extern unsigned long pci_dram_offset;
+
+extern resource_size_t isa_mem_base;
 
 #define IO_SPACE_LIMIT (0xFFFFFFFF)
 
@@ -124,9 +140,6 @@ static inline void writel(unsigned int v, volatile void __iomem *addr)
 #define virt_to_phys(addr)     ((unsigned long)__virt_to_phys(addr))
 #define virt_to_bus(addr)      ((unsigned long)__virt_to_phys(addr))
 
-#define __page_address(page) \
-               (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
-#define page_to_phys(page)     virt_to_phys((void *)__page_address(page))
 #define page_to_bus(page)      (page_to_phys(page))
 #define bus_to_virt(addr)      (phys_to_virt(addr))
 
@@ -227,15 +240,7 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
 #define out_8(a, v) __raw_writeb((v), (a))
 #define in_8(a) __raw_readb(a)
 
-/* FIXME */
-static inline void __iomem *ioport_map(unsigned long port, unsigned int len)
-{
-       return (void __iomem *) (port);
-}
-
-static inline void ioport_unmap(void __iomem *addr)
-{
-       /* Nothing to do */
-}
+#define ioport_map(port, nr)   ((void __iomem *)(port))
+#define ioport_unmap(addr)
 
 #endif /* _ASM_MICROBLAZE_IO_H */
index 90f0505..31a35c3 100644 (file)
 
 #include <linux/interrupt.h>
 
+/* This type is the placeholder for a hardware interrupt number. It has to
+ * be big enough to enclose whatever representation is used by a given
+ * platform.
+ */
+typedef unsigned long irq_hw_number_t;
+
 extern unsigned int nr_irq;
 
 #define NO_IRQ (-1)
@@ -21,7 +27,8 @@ extern unsigned int nr_irq;
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
-/* irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
+/**
+ * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
  * @device: Device node of the device whose interrupt is to be mapped
  * @index: Index of the interrupt to map
  *
@@ -40,4 +47,32 @@ static inline void irq_dispose_mapping(unsigned int virq)
        return;
 }
 
+struct irq_host;
+
+/**
+ * irq_create_mapping - Map a hardware interrupt into linux virq space
+ * @host: host owning this hardware interrupt or NULL for default host
+ * @hwirq: hardware irq number in that host space
+ *
+ * Only one mapping per hardware interrupt is permitted. Returns a linux
+ * virq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
+ */
+extern unsigned int irq_create_mapping(struct irq_host *host,
+                                       irq_hw_number_t hwirq);
+
+/**
+ * irq_create_of_mapping - Map a hardware interrupt into linux virq space
+ * @controller: Device node of the interrupt controller
+ * @inspec: Interrupt specifier from the device-tree
+ * @intsize: Size of the interrupt specifier from the device-tree
+ *
+ * This function is identical to irq_create_mapping except that it takes
+ * as input informations straight from the device-tree (typically the results
+ * of the of_irq_map_*() functions.
+ */
+extern unsigned int irq_create_of_mapping(struct device_node *controller,
+                                       u32 *intspec, unsigned int intsize);
+
 #endif /* _ASM_MICROBLAZE_IRQ_H */
index 9b66c0f..2dd1d04 100644 (file)
@@ -62,12 +62,6 @@ extern unsigned int __page_offset;
 #define PAGE_OFFSET    CONFIG_KERNEL_START
 
 /*
- * MAP_NR -- given an address, calculate the index of the page struct which
- * points to the address's page.
- */
-#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
-
-/*
  * The basic type of a PTE - 32 bit physical addressing.
  */
 typedef unsigned long pte_basic_t;
@@ -154,7 +148,11 @@ extern int page_is_ram(unsigned long pfn);
 # define pfn_to_virt(pfn)      __va(pfn_to_phys((pfn)))
 
 #  ifdef CONFIG_MMU
-#  define virt_to_page(kaddr)  (mem_map +  MAP_NR(kaddr))
+
+#  define virt_to_page(kaddr)  (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
+#  define page_to_virt(page)   __va(page_to_pfn(page) << PAGE_SHIFT)
+#  define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+
 #  else /* CONFIG_MMU */
 #  define virt_to_page(vaddr)  (pfn_to_page(virt_to_pfn(vaddr)))
 #  define page_to_virt(page)   (pfn_to_virt(page_to_pfn(page)))
index 7ad28f6..0c77cda 100644 (file)
@@ -1 +1,196 @@
+#ifndef _ASM_MICROBLAZE_PCI_BRIDGE_H
+#define _ASM_MICROBLAZE_PCI_BRIDGE_H
+#ifdef __KERNEL__
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
 #include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+
+struct device_node;
+
+enum {
+       /* Force re-assigning all resources (ignore firmware
+        * setup completely)
+        */
+       PCI_REASSIGN_ALL_RSRC   = 0x00000001,
+
+       /* Re-assign all bus numbers */
+       PCI_REASSIGN_ALL_BUS    = 0x00000002,
+
+       /* Do not try to assign, just use existing setup */
+       PCI_PROBE_ONLY          = 0x00000004,
+
+       /* Don't bother with ISA alignment unless the bridge has
+        * ISA forwarding enabled
+        */
+       PCI_CAN_SKIP_ISA_ALIGN  = 0x00000008,
+
+       /* Enable domain numbers in /proc */
+       PCI_ENABLE_PROC_DOMAINS = 0x00000010,
+       /* ... except for domain 0 */
+       PCI_COMPAT_DOMAIN_0             = 0x00000020,
+};
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct pci_controller {
+       struct pci_bus *bus;
+       char is_dynamic;
+       struct device_node *dn;
+       struct list_head list_node;
+       struct device *parent;
+
+       int first_busno;
+       int last_busno;
+
+       int self_busno;
+
+       void __iomem *io_base_virt;
+       resource_size_t io_base_phys;
+
+       resource_size_t pci_io_size;
+
+       /* Some machines (PReP) have a non 1:1 mapping of
+        * the PCI memory space in the CPU bus space
+        */
+       resource_size_t pci_mem_offset;
+
+       /* Some machines have a special region to forward the ISA
+        * "memory" cycles such as VGA memory regions. Left to 0
+        * if unsupported
+        */
+       resource_size_t isa_mem_phys;
+       resource_size_t isa_mem_size;
+
+       struct pci_ops *ops;
+       unsigned int __iomem *cfg_addr;
+       void __iomem *cfg_data;
+
+       /*
+        * Used for variants of PCI indirect handling and possible quirks:
+        *  SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
+        *  EXT_REG - provides access to PCI-e extended registers
+        *  SURPRESS_PRIMARY_BUS - we surpress the setting of PCI_PRIMARY_BUS
+        *   on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS
+        *   to determine which bus number to match on when generating type0
+        *   config cycles
+        *  NO_PCIE_LINK - the Freescale PCI-e controllers have issues with
+        *   hanging if we don't have link and try to do config cycles to
+        *   anything but the PHB.  Only allow talking to the PHB if this is
+        *   set.
+        *  BIG_ENDIAN - cfg_addr is a big endian register
+        *  BROKEN_MRM - the 440EPx/GRx chips have an errata that causes hangs
+        *   on the PLB4.  Effectively disable MRM commands by setting this.
+        */
+#define INDIRECT_TYPE_SET_CFG_TYPE             0x00000001
+#define INDIRECT_TYPE_EXT_REG          0x00000002
+#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS     0x00000004
+#define INDIRECT_TYPE_NO_PCIE_LINK             0x00000008
+#define INDIRECT_TYPE_BIG_ENDIAN               0x00000010
+#define INDIRECT_TYPE_BROKEN_MRM               0x00000020
+       u32 indirect_type;
+
+       /* Currently, we limit ourselves to 1 IO range and 3 mem
+        * ranges since the common pci_bus structure can't handle more
+        */
+       struct resource io_resource;
+       struct resource mem_resources[3];
+       int global_number;      /* PCI domain number */
+};
+
+static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
+{
+       return bus->sysdata;
+}
+
+static inline int isa_vaddr_is_ioport(void __iomem *address)
+{
+       /* No specific ISA handling on ppc32 at this stage, it
+        * all goes through PCI
+        */
+       return 0;
+}
+
+/* These are used for config access before all the PCI probing
+   has been done. */
+extern int early_read_config_byte(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u8 *val);
+extern int early_read_config_word(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u16 *val);
+extern int early_read_config_dword(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u32 *val);
+extern int early_write_config_byte(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u8 val);
+extern int early_write_config_word(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u16 val);
+extern int early_write_config_dword(struct pci_controller *hose, int bus,
+                       int dev_fn, int where, u32 val);
+
+extern int early_find_capability(struct pci_controller *hose, int bus,
+                                int dev_fn, int cap);
+
+extern void setup_indirect_pci(struct pci_controller *hose,
+                              resource_size_t cfg_addr,
+                              resource_size_t cfg_data, u32 flags);
+
+/* Get the PCI host controller for an OF device */
+extern struct pci_controller *pci_find_hose_for_OF_device(
+                       struct device_node *node);
+
+/* Fill up host controller resources from the OF node */
+extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+                       struct device_node *dev, int primary);
+
+/* Allocate & free a PCI host bridge structure */
+extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
+extern void pcibios_free_controller(struct pci_controller *phb);
+extern void pcibios_setup_phb_resources(struct pci_controller *hose);
+
+#ifdef CONFIG_PCI
+extern unsigned int pci_flags;
+
+static inline void pci_set_flags(int flags)
+{
+       pci_flags = flags;
+}
+
+static inline void pci_add_flags(int flags)
+{
+       pci_flags |= flags;
+}
+
+static inline int pci_has_flag(int flag)
+{
+       return pci_flags & flag;
+}
+
+extern struct list_head hose_list;
+
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+extern int pcibios_vaddr_is_ioport(void __iomem *address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       return (unsigned long)-1;
+}
+static inline int pcibios_vaddr_is_ioport(void __iomem *address)
+{
+       return 0;
+}
+
+static inline void pci_set_flags(int flags) { }
+static inline void pci_add_flags(int flags) { }
+static inline int pci_has_flag(int flag)
+{
+       return 0;
+}
+#endif /* CONFIG_PCI */
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */
index 9f0df5f..bdd65aa 100644 (file)
@@ -1 +1,177 @@
-#include <asm-generic/pci.h>
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on powerpc version
+ */
+
+#ifndef __ASM_MICROBLAZE_PCI_H
+#define __ASM_MICROBLAZE_PCI_H
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#define PCIBIOS_MIN_IO         0x1000
+#define PCIBIOS_MIN_MEM                0x10000000
+
+struct pci_dev;
+
+/* Values for the `which' argument to sys_pciconfig_iobase syscall.  */
+#define IOBASE_BRIDGE_NUMBER   0
+#define IOBASE_MEMORY          1
+#define IOBASE_IO              2
+#define IOBASE_ISA_IO          3
+#define IOBASE_ISA_MEM         4
+
+#define pcibios_scan_all_fns(a, b)     0
+
+/*
+ * Set this to 1 if you want the kernel to re-assign all PCI
+ * bus numbers (don't do that on ppc64 yet !)
+ */
+#define pcibios_assign_all_busses() \
+       (pci_has_flag(PCI_REASSIGN_ALL_BUS))
+
+static inline void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
+static inline void pcibios_penalize_isa_irq(int irq, int active)
+{
+       /* We don't do dynamic PCI IRQ allocation */
+}
+
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_map_ops *dma_ops);
+extern struct dma_map_ops *get_pci_dma_ops(void);
+#else  /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops()      NULL
+#endif
+
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
+extern int pci_domain_nr(struct pci_bus *bus);
+
+/* Decide whether to display the domain number in /proc */
+extern int pci_proc_domain(struct pci_bus *bus);
+
+struct vm_area_struct;
+/* Map a range of PCI memory or I/O space for a device into user space */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state, int write_combine);
+
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
+#define HAVE_PCI_MMAP  1
+
+extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
+                          size_t count);
+extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
+                          size_t count);
+extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
+                                     struct vm_area_struct *vma,
+                                     enum pci_mmap_state mmap_state);
+
+#define HAVE_PCI_LEGACY        1
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)           (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+
+/* The PCI address space does equal the physical memory
+ * address space (no IOMMU).  The IDE and SCSI device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (1)
+
+extern void pcibios_resource_to_bus(struct pci_dev *dev,
+                       struct pci_bus_region *region,
+                       struct resource *res);
+
+extern void pcibios_bus_to_resource(struct pci_dev *dev,
+                       struct resource *res,
+                       struct pci_bus_region *region);
+
+static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
+                       struct resource *res)
+{
+       struct resource *root = NULL;
+
+       if (res->flags & IORESOURCE_IO)
+               root = &ioport_resource;
+       if (res->flags & IORESOURCE_MEM)
+               root = &iomem_resource;
+
+       return root;
+}
+
+extern void pcibios_claim_one_bus(struct pci_bus *b);
+
+extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
+
+extern void pcibios_resource_survey(void);
+
+extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
+extern int remove_phb_dynamic(struct pci_controller *phb);
+
+extern struct pci_dev *of_create_pci_dev(struct device_node *node,
+                                       struct pci_bus *bus, int devfn);
+
+extern void of_scan_pci_bridge(struct device_node *node,
+                               struct pci_dev *dev);
+
+extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
+extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus);
+
+extern int pci_read_irq_line(struct pci_dev *dev);
+
+extern int pci_bus_find_capability(struct pci_bus *bus,
+                                               unsigned int devfn, int cap);
+
+struct file;
+extern pgprot_t        pci_phys_mem_access_prot(struct file *file,
+                                        unsigned long pfn,
+                                        unsigned long size,
+                                        pgprot_t prot);
+
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                                const struct resource *rsrc,
+                                resource_size_t *start, resource_size_t *end);
+
+extern void pcibios_setup_bus_devices(struct pci_bus *bus);
+extern void pcibios_setup_bus_self(struct pci_bus *bus);
+
+/* This part of code was originaly in xilinx-pci.h */
+#ifdef CONFIG_PCI_XILINX
+extern void __init xilinx_pci_init(void);
+#else
+static inline void __init xilinx_pci_init(void) { return; }
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_MICROBLAZE_PCI_H */
index 7547f50..f44b0d6 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/cache.h>
+#include <asm/pgtable.h>
 
 #define PGDIR_ORDER    0
 
@@ -111,7 +112,6 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                unsigned long address)
 {
        pte_t *pte;
-       extern int mem_init_done;
        extern void *early_get_page(void);
        if (mem_init_done) {
                pte = (pte_t *)__get_free_page(GFP_KERNEL |
index cc3a4df..dd2bb60 100644 (file)
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
+#ifndef __ASSEMBLY__
+extern int mem_init_done;
+#endif
+
 #ifndef CONFIG_MMU
 
 #define pgd_present(pgd)       (1) /* pages are always present on non MMU */
@@ -51,6 +55,8 @@ static inline int pte_file(pte_t pte) { return 0; }
 
 #define arch_enter_lazy_cpu_mode()     do {} while (0)
 
+#define pgprot_noncached_wc(prot)      prot
+
 #else /* CONFIG_MMU */
 
 #include <asm-generic/4level-fixup.h>
@@ -68,7 +74,6 @@ static inline int pte_file(pte_t pte) { return 0; }
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(unsigned long address);
-extern unsigned long ioremap_bot, ioremap_base;
 
 /*
  * The following only work if pte_present() is true.
@@ -85,11 +90,25 @@ static inline pte_t pte_mkspecial(pte_t pte)        { return pte; }
 #define VMALLOC_START  (CONFIG_KERNEL_START + \
                                max(32 * 1024 * 1024UL, memory_size))
 #define VMALLOC_END    ioremap_bot
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
 #endif /* __ASSEMBLY__ */
 
 /*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL        (_PAGE_GUARDED | _PAGE_NO_CACHE | \
+                                                       _PAGE_WRITETHRU)
+
+#define pgprot_noncached(prot) \
+                       (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+                                       _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+#define pgprot_noncached_wc(prot) \
+                        (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+                                                       _PAGE_NO_CACHE))
+
+/*
  * The MicroBlaze MMU is identical to the PPC-40x MMU, and uses a hash
  * table containing PTEs, together with a set of 16 segment registers, to
  * define the virtual to physical address mapping.
@@ -397,7 +416,7 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr,
        mts     rmsr, %2\n\
        nop"
        : "=&r" (old), "=&r" (tmp), "=&r" (msr), "=m" (*p)
-       : "r" ((unsigned long)(p+1) - 4), "r" (clr), "r" (set), "m" (*p)
+       : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set), "m" (*p)
        : "cc");
 
        return old;
@@ -566,18 +585,11 @@ void mapin_ram(void);
 int map_page(unsigned long va, phys_addr_t pa, int flags);
 
 extern int mem_init_done;
-extern unsigned long ioremap_base;
-extern unsigned long ioremap_bot;
 
 asmlinkage void __init mmu_init(void);
 
 void __init *early_get_page(void);
 
-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
-void consistent_free(void *vaddr);
-void consistent_sync(void *vaddr, size_t size, int direction);
-void consistent_sync_page(struct page *page, unsigned long offset,
-       size_t size, int direction);
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 
@@ -586,6 +598,14 @@ void consistent_sync_page(struct page *page, unsigned long offset,
 #ifndef __ASSEMBLY__
 #include <asm-generic/pgtable.h>
 
+extern unsigned long ioremap_bot, ioremap_base;
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
+void consistent_free(void *vaddr);
+void consistent_sync(void *vaddr, size_t size, int direction);
+void consistent_sync_page(struct page *page, unsigned long offset,
+       size_t size, int direction);
+
 void setup_memory(void);
 #endif /* __ASSEMBLY__ */
 
index 03f45a9..e7d67a3 100644 (file)
 /* Other Prototypes */
 extern int early_uartlite_console(void);
 
+#ifdef CONFIG_PCI
+/*
+ * PCI <-> OF matching functions
+ * (XXX should these be here?)
+ */
+struct pci_bus;
+struct pci_dev;
+extern int pci_device_from_OF_node(struct device_node *node,
+                                       u8 *bus, u8 *devfn);
+extern struct device_node *pci_busdev_to_OF_node(struct pci_bus *bus,
+                                                       int devfn);
+extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
+extern void pci_create_OF_bus_map(void);
+#endif
+
 /*
  * OF address retreival & translation
  */
index 1579706..59efb3f 100644 (file)
@@ -87,6 +87,9 @@ void free_initmem(void);
 extern char *klimit;
 extern void ret_from_fork(void);
 
+extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
+extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *of_debugfs_root;
 #endif
index 10ec70c..bcb8b41 100644 (file)
@@ -23,7 +23,7 @@
 extern void _tlbie(unsigned long address);
 extern void _tlbia(void);
 
-#define __tlbia()      _tlbia()
+#define __tlbia()      { preempt_disable(); _tlbia(); preempt_enable(); }
 
 static inline void local_flush_tlb_all(void)
        { __tlbia(); }
index b07594e..e51bc15 100644 (file)
@@ -14,7 +14,7 @@ endif
 
 extra-y := head.o vmlinux.lds
 
-obj-y += exceptions.o \
+obj-y += dma.o exceptions.o \
        hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
        of_platform.o process.o prom.o prom_parse.o ptrace.o \
        setup.o signal.o sys_microblaze.o timer.o traps.o reset.o
index 7bc7b68..0071260 100644 (file)
@@ -90,6 +90,7 @@ int main(int argc, char *argv[])
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
        DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
        DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
+       DEFINE(TI_PREEMPT_COUNT, offsetof(struct thread_info, preempt_count));
        BLANK();
 
        /* struct cpu_context */
index 2a56bcc..f04d8a8 100644 (file)
 #include <asm/cpuinfo.h>
 #include <asm/pvr.h>
 
-static inline void __invalidate_flush_icache(unsigned int addr)
-{
-       __asm__ __volatile__ ("wic      %0, r0;"        \
-                                       : : "r" (addr));
-}
-
-static inline void __flush_dcache(unsigned int addr)
-{
-       __asm__ __volatile__ ("wdc.flush        %0, r0;"        \
-                                       : : "r" (addr));
-}
-
-static inline void __invalidate_dcache(unsigned int baseaddr,
-                                               unsigned int offset)
-{
-       __asm__ __volatile__ ("wdc.clear        %0, %1;"        \
-                                       : : "r" (baseaddr), "r" (offset));
-}
-
 static inline void __enable_icache_msr(void)
 {
        __asm__ __volatile__ (" msrset  r0, %0;         \
@@ -148,9 +129,9 @@ do {                                                                        \
        int step = -line_length;                                        \
        BUG_ON(step >= 0);                                              \
                                                                        \
-       __asm__ __volatile__ (" 1:      " #op " r0, %0;                 \
-                                       bgtid   %0, 1b;                 \
-                                       addk    %0, %0, %1;             \
+       __asm__ __volatile__ (" 1:      " #op " r0, %0;                 \
+                                       bgtid   %0, 1b;                 \
+                                       addk    %0, %0, %1;             \
                                        " : : "r" (len), "r" (step)     \
                                        : "memory");                    \
 } while (0);
@@ -162,9 +143,9 @@ do {                                                                        \
        int count = end - start;                                        \
        BUG_ON(count <= 0);                                             \
                                                                        \
-       __asm__ __volatile__ (" 1:      " #op " %0, %1;                 \
-                                       bgtid   %1, 1b;                 \
-                                       addk    %1, %1, %2;             \
+       __asm__ __volatile__ (" 1:      " #op " %0, %1;                 \
+                                       bgtid   %1, 1b;                 \
+                                       addk    %1, %1, %2;             \
                                        " : : "r" (start), "r" (count), \
                                        "r" (step) : "memory");         \
 } while (0);
@@ -175,7 +156,7 @@ do {                                                                        \
        int volatile temp;                                              \
        BUG_ON(end - start <= 0);                                       \
                                                                        \
-       __asm__ __volatile__ (" 1:      " #op " %1, r0;                 \
+       __asm__ __volatile__ (" 1:      " #op " %1, r0;                 \
                                        cmpu    %0, %1, %2;             \
                                        bgtid   %0, 1b;                 \
                                        addk    %1, %1, %3;             \
@@ -183,10 +164,14 @@ do {                                                                      \
                                        "r" (line_length) : "memory");  \
 } while (0);
 
+#define ASM_LOOP
+
 static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
@@ -196,8 +181,13 @@ static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
        local_irq_save(flags);
        __disable_icache_msr();
 
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
-
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wic      %0, r0;"        \
+                               : : "r" (i));
+#endif
        __enable_icache_msr();
        local_irq_restore(flags);
 }
@@ -206,7 +196,9 @@ static void __flush_icache_range_nomsr_irq(unsigned long start,
                                unsigned long end)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
@@ -216,7 +208,13 @@ static void __flush_icache_range_nomsr_irq(unsigned long start,
        local_irq_save(flags);
        __disable_icache_nomsr();
 
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wic      %0, r0;"        \
+                               : : "r" (i));
+#endif
 
        __enable_icache_nomsr();
        local_irq_restore(flags);
@@ -225,25 +223,41 @@ static void __flush_icache_range_nomsr_irq(unsigned long start,
 static void __flush_icache_range_noirq(unsigned long start,
                                unsigned long end)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
        CACHE_LOOP_LIMITS(start, end,
                        cpuinfo.icache_line_length, cpuinfo.icache_size);
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wic      %0, r0;"        \
+                               : : "r" (i));
+#endif
 }
 
 static void __flush_icache_all_msr_irq(void)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
 
        local_irq_save(flags);
        __disable_icache_msr();
-
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
-
+#else
+       for (i = 0; i < cpuinfo.icache_size;
+                i += cpuinfo.icache_line_length)
+                       __asm__ __volatile__ ("wic      %0, r0;" \
+                                       : : "r" (i));
+#endif
        __enable_icache_msr();
        local_irq_restore(flags);
 }
@@ -251,35 +265,59 @@ static void __flush_icache_all_msr_irq(void)
 static void __flush_icache_all_nomsr_irq(void)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
 
        local_irq_save(flags);
        __disable_icache_nomsr();
-
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
-
+#else
+       for (i = 0; i < cpuinfo.icache_size;
+                i += cpuinfo.icache_line_length)
+                       __asm__ __volatile__ ("wic      %0, r0;" \
+                                       : : "r" (i));
+#endif
        __enable_icache_nomsr();
        local_irq_restore(flags);
 }
 
 static void __flush_icache_all_noirq(void)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
+#else
+       for (i = 0; i < cpuinfo.icache_size;
+                i += cpuinfo.icache_line_length)
+                       __asm__ __volatile__ ("wic      %0, r0;" \
+                                       : : "r" (i));
+#endif
 }
 
 static void __invalidate_dcache_all_msr_irq(void)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
 
        local_irq_save(flags);
        __disable_dcache_msr();
-
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
-
+#else
+       for (i = 0; i < cpuinfo.dcache_size;
+                i += cpuinfo.dcache_line_length)
+                       __asm__ __volatile__ ("wdc      %0, r0;" \
+                                       : : "r" (i));
+#endif
        __enable_dcache_msr();
        local_irq_restore(flags);
 }
@@ -287,60 +325,107 @@ static void __invalidate_dcache_all_msr_irq(void)
 static void __invalidate_dcache_all_nomsr_irq(void)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
 
        local_irq_save(flags);
        __disable_dcache_nomsr();
-
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
-
+#else
+       for (i = 0; i < cpuinfo.dcache_size;
+                i += cpuinfo.dcache_line_length)
+                       __asm__ __volatile__ ("wdc      %0, r0;" \
+                                       : : "r" (i));
+#endif
        __enable_dcache_nomsr();
        local_irq_restore(flags);
 }
 
 static void __invalidate_dcache_all_noirq_wt(void)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
+#else
+       for (i = 0; i < cpuinfo.dcache_size;
+                i += cpuinfo.dcache_line_length)
+                       __asm__ __volatile__ ("wdc      %0, r0;" \
+                                       : : "r" (i));
+#endif
 }
 
 /* FIXME this is weird - should be only wdc but not work
  * MS: I am getting bus errors and other weird things */
 static void __invalidate_dcache_all_wb(void)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
                                        wdc.clear)
+#else
+       for (i = 0; i < cpuinfo.dcache_size;
+                i += cpuinfo.dcache_line_length)
+                       __asm__ __volatile__ ("wdc.clear        %0, r0;" \
+                                       : : "r" (i));
+#endif
 }
 
 static void __invalidate_dcache_range_wb(unsigned long start,
                                                unsigned long end)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
        CACHE_LOOP_LIMITS(start, end,
                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wdc.clear        %0, r0;"        \
+                               : : "r" (i));
+#endif
 }
 
 static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
                                                        unsigned long end)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
        CACHE_LOOP_LIMITS(start, end,
                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wdc      %0, r0;"        \
+                               : : "r" (i));
+#endif
 }
 
 static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
                                                        unsigned long end)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
        CACHE_LOOP_LIMITS(start, end,
@@ -349,7 +434,13 @@ static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
        local_irq_save(flags);
        __disable_dcache_msr();
 
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wdc      %0, r0;"        \
+                               : : "r" (i));
+#endif
 
        __enable_dcache_msr();
        local_irq_restore(flags);
@@ -359,7 +450,9 @@ static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
                                                        unsigned long end)
 {
        unsigned long flags;
-
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
@@ -369,7 +462,13 @@ static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
        local_irq_save(flags);
        __disable_dcache_nomsr();
 
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wdc      %0, r0;"        \
+                               : : "r" (i));
+#endif
 
        __enable_dcache_nomsr();
        local_irq_restore(flags);
@@ -377,19 +476,38 @@ static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
 
 static void __flush_dcache_all_wb(void)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s\n", __func__);
+#ifdef ASM_LOOP
        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
                                wdc.flush);
+#else
+       for (i = 0; i < cpuinfo.dcache_size;
+                i += cpuinfo.dcache_line_length)
+                       __asm__ __volatile__ ("wdc.flush        %0, r0;" \
+                                       : : "r" (i));
+#endif
 }
 
 static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
 {
+#ifndef ASM_LOOP
+       int i;
+#endif
        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
                                (unsigned int)start, (unsigned int) end);
 
        CACHE_LOOP_LIMITS(start, end,
                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+#ifdef ASM_LOOP
        CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
+#else
+       for (i = start; i < end; i += cpuinfo.icache_line_length)
+               __asm__ __volatile__ ("wdc.flush        %0, r0;"        \
+                               : : "r" (i));
+#endif
 }
 
 /* struct for wb caches and for wt caches */
@@ -493,7 +611,7 @@ const struct scache wt_nomsr_noirq = {
 #define CPUVER_7_20_A  0x0c
 #define CPUVER_7_20_D  0x0f
 
-#define INFO(s)        printk(KERN_INFO "cache: " s " \n");
+#define INFO(s)        printk(KERN_INFO "cache: " s "\n");
 
 void microblaze_cache_init(void)
 {
@@ -532,4 +650,9 @@ void microblaze_cache_init(void)
                        }
                }
        }
+       invalidate_dcache();
+       enable_dcache();
+
+       invalidate_icache();
+       enable_icache();
 }
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
new file mode 100644 (file)
index 0000000..b108497
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009-2010 PetaLogix
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-debug.h>
+#include <asm/bug.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Generic direct DMA implementation
+ *
+ * This implementation supports a per-device offset that can be applied if
+ * the address at which memory is visible to devices is not 0. Platform code
+ * can set archdata.dma_data to an unsigned long holding the offset. By
+ * default the offset is PCI_DRAM_OFFSET.
+ */
+static inline void __dma_sync_page(unsigned long paddr, unsigned long offset,
+                               size_t size, enum dma_data_direction direction)
+{
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               flush_dcache_range(paddr + offset, paddr + offset + size);
+               break;
+       case DMA_FROM_DEVICE:
+               invalidate_dcache_range(paddr + offset, paddr + offset + size);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static unsigned long get_dma_direct_offset(struct device *dev)
+{
+       if (dev)
+               return (unsigned long)dev->archdata.dma_data;
+
+       return PCI_DRAM_OFFSET; /* FIXME Not sure if is correct */
+}
+
+#define NOT_COHERENT_CACHE
+
+static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef NOT_COHERENT_CACHE
+       return consistent_alloc(flag, size, dma_handle);
+#else
+       void *ret;
+       struct page *page;
+       int node = dev_to_node(dev);
+
+       /* ignore region specifiers */
+       flag  &= ~(__GFP_HIGHMEM);
+
+       page = alloc_pages_node(node, flag, get_order(size));
+       if (page == NULL)
+               return NULL;
+       ret = page_address(page);
+       memset(ret, 0, size);
+       *dma_handle = virt_to_phys(ret) + get_dma_direct_offset(dev);
+
+       return ret;
+#endif
+}
+
+static void dma_direct_free_coherent(struct device *dev, size_t size,
+                             void *vaddr, dma_addr_t dma_handle)
+{
+#ifdef NOT_COHERENT_CACHE
+       consistent_free(vaddr);
+#else
+       free_pages((unsigned long)vaddr, get_order(size));
+#endif
+}
+
+static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
+                            int nents, enum dma_data_direction direction,
+                            struct dma_attrs *attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       /* FIXME this part of code is untested */
+       for_each_sg(sgl, sg, nents, i) {
+               sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
+               sg->dma_length = sg->length;
+               __dma_sync_page(page_to_phys(sg_page(sg)), sg->offset,
+                                                       sg->length, direction);
+       }
+
+       return nents;
+}
+
+static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nents, enum dma_data_direction direction,
+                               struct dma_attrs *attrs)
+{
+}
+
+static int dma_direct_dma_supported(struct device *dev, u64 mask)
+{
+       return 1;
+}
+
+static inline dma_addr_t dma_direct_map_page(struct device *dev,
+                                            struct page *page,
+                                            unsigned long offset,
+                                            size_t size,
+                                            enum dma_data_direction direction,
+                                            struct dma_attrs *attrs)
+{
+       __dma_sync_page(page_to_phys(page), offset, size, direction);
+       return page_to_phys(page) + offset + get_dma_direct_offset(dev);
+}
+
+static inline void dma_direct_unmap_page(struct device *dev,
+                                        dma_addr_t dma_address,
+                                        size_t size,
+                                        enum dma_data_direction direction,
+                                        struct dma_attrs *attrs)
+{
+/* There is not necessary to do cache cleanup
+ *
+ * phys_to_virt is here because in __dma_sync_page is __virt_to_phys and
+ * dma_address is physical address
+ */
+       __dma_sync_page(dma_address, 0 , size, direction);
+}
+
+struct dma_map_ops dma_direct_ops = {
+       .alloc_coherent = dma_direct_alloc_coherent,
+       .free_coherent  = dma_direct_free_coherent,
+       .map_sg         = dma_direct_map_sg,
+       .unmap_sg       = dma_direct_unmap_sg,
+       .dma_supported  = dma_direct_dma_supported,
+       .map_page       = dma_direct_map_page,
+       .unmap_page     = dma_direct_unmap_page,
+};
+EXPORT_SYMBOL(dma_direct_ops);
+
+/* Number of entries preallocated for DMA-API debugging */
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+       return 0;
+}
+fs_initcall(dma_init);
index 3bad4ff..c0ede25 100644 (file)
@@ -305,7 +305,7 @@ C_ENTRY(_user_exception):
        swi     r11, r1, PTO+PT_R1;             /* Store user SP.  */
        addi    r11, r0, 1;
        swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
-2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        /* Save away the syscall number.  */
        swi     r12, r1, PTO+PT_R0;
        tovirt(r1,r1)
@@ -322,8 +322,7 @@ C_ENTRY(_user_exception):
        rtid    r11, 0
        nop
 3:
-       add     r11, r0, CURRENT_TASK    /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO /* get thread info */
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
        lwi     r11, r11, TI_FLAGS       /* get flags in thread info */
        andi    r11, r11, _TIF_WORK_SYSCALL_MASK
        beqi    r11, 4f
@@ -382,60 +381,50 @@ C_ENTRY(ret_from_trap):
 /* See if returning to kernel mode, if so, skip resched &c.  */
        bnei    r11, 2f;
 
+       swi     r3, r1, PTO + PT_R3
+       swi     r4, r1, PTO + PT_R4
+
        /* We're returning to user mode, so check for various conditions that
         * trigger rescheduling. */
-       # FIXME: Restructure all these flag checks.
-       add     r11, r0, CURRENT_TASK;  /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       /* FIXME: Restructure all these flag checks. */
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;             /* get flags in thread info */
        andi    r11, r11, _TIF_WORK_SYSCALL_MASK
        beqi    r11, 1f
 
-       swi     r3, r1, PTO + PT_R3
-       swi     r4, r1, PTO + PT_R4
        brlid   r15, do_syscall_trace_leave
        addik   r5, r1, PTO + PT_R0
-       lwi     r3, r1, PTO + PT_R3
-       lwi     r4, r1, PTO + PT_R4
 1:
-
        /* We're returning to user mode, so check for various conditions that
         * trigger rescheduling. */
-       /* Get current task ptr into r11 */
-       add     r11, r0, CURRENT_TASK;  /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       /* get thread info from current task */
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;
        lwi     r11, r11, TI_FLAGS;             /* get flags in thread info */
        andi    r11, r11, _TIF_NEED_RESCHED;
        beqi    r11, 5f;
 
-       swi     r3, r1, PTO + PT_R3; /* store syscall result */
-       swi     r4, r1, PTO + PT_R4;
        bralid  r15, schedule;  /* Call scheduler */
        nop;                            /* delay slot */
-       lwi     r3, r1, PTO + PT_R3; /* restore syscall result */
-       lwi     r4, r1, PTO + PT_R4;
 
        /* Maybe handle a signal */
-5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+5:     /* get thread info from current task*/
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_SIGPENDING;
        beqi    r11, 1f;                /* Signals to handle, handle them */
 
-       swi     r3, r1, PTO + PT_R3; /* store syscall result */
-       swi     r4, r1, PTO + PT_R4;
        la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
-       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
        addi    r7, r0, 1;              /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
-       nop;
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
+
+/* Finally, return to user state.  */
+1:
        lwi     r3, r1, PTO + PT_R3; /* restore syscall result */
        lwi     r4, r1, PTO + PT_R4;
 
-/* Finally, return to user state.  */
-1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
-       add     r11, r0, CURRENT_TASK;  /* Get current task ptr into r11 */
-       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
        RESTORE_REGS;
@@ -565,7 +554,7 @@ C_ENTRY(sys_rt_sigreturn_wrapper):
        swi     r11, r1, PTO+PT_R1; /* Store user SP.  */               \
        addi    r11, r0, 1;                                             \
        swi     r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\
-2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));        \
        /* Save away the syscall number.  */                            \
        swi     r0, r1, PTO+PT_R0;                                      \
        tovirt(r1,r1)
@@ -673,9 +662,7 @@ C_ENTRY(ret_from_exc):
 
        /* We're returning to user mode, so check for various conditions that
           trigger rescheduling. */
-       /* Get current task ptr into r11 */
-       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_NEED_RESCHED;
        beqi    r11, 5f;
@@ -685,8 +672,7 @@ C_ENTRY(ret_from_exc):
        nop;                            /* delay slot */
 
        /* Maybe handle a signal */
-5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+5:     lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_SIGPENDING;
        beqi    r11, 1f;                /* Signals to handle, handle them */
@@ -705,15 +691,13 @@ C_ENTRY(ret_from_exc):
         * store return registers separately because this macros is use
         * for others exceptions */
        la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
-       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
        addi    r7, r0, 0;              /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
-       nop;
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
 
 /* Finally, return to user state.  */
 1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
-       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
 
@@ -802,7 +786,7 @@ C_ENTRY(_interrupt):
        swi     r11, r0, TOPHYS(PER_CPU(KM));
 
 2:
-       lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+       lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        swi     r0, r1, PTO + PT_R0;
        tovirt(r1,r1)
        la      r5, r1, PTO;
@@ -817,8 +801,7 @@ ret_from_irq:
        lwi     r11, r1, PTO + PT_MODE;
        bnei    r11, 2f;
 
-       add     r11, r0, CURRENT_TASK;
-       lwi     r11, r11, TS_THREAD_INFO;
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;
        lwi     r11, r11, TI_FLAGS; /* MS: get flags from thread info */
        andi    r11, r11, _TIF_NEED_RESCHED;
        beqi    r11, 5f
@@ -826,8 +809,7 @@ ret_from_irq:
        nop; /* delay slot */
 
     /* Maybe handle a signal */
-5:     add     r11, r0, CURRENT_TASK;
-       lwi     r11, r11, TS_THREAD_INFO; /* MS: get thread info */
+5:     lwi     r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
        lwi     r11, r11, TI_FLAGS; /* get flags in thread info */
        andi    r11, r11, _TIF_SIGPENDING;
        beqid   r11, no_intr_resched
@@ -842,8 +824,7 @@ no_intr_resched:
     /* Disable interrupts, we are now committed to the state restore */
        disable_irq
        swi     r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */
-       add     r11, r0, CURRENT_TASK;
-       swi     r11, r0, PER_CPU(CURRENT_SAVE);
+       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
        VM_OFF;
        tophys(r1,r1);
        lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
@@ -853,7 +834,28 @@ no_intr_resched:
        lwi     r1, r1, PT_R1 - PT_SIZE;
        bri     6f;
 /* MS: Return to kernel state. */
-2:     VM_OFF /* MS: turn off MMU */
+2:
+#ifdef CONFIG_PREEMPT
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;
+       /* MS: get preempt_count from thread info */
+       lwi     r5, r11, TI_PREEMPT_COUNT;
+       bgti    r5, restore;
+
+       lwi     r5, r11, TI_FLAGS;              /* get flags in thread info */
+       andi    r5, r5, _TIF_NEED_RESCHED;
+       beqi    r5, restore /* if zero jump over */
+
+preempt:
+       /* interrupts are off that's why I am calling preempt_chedule_irq */
+       bralid  r15, preempt_schedule_irq
+       nop
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
+       lwi     r5, r11, TI_FLAGS;              /* get flags in thread info */
+       andi    r5, r5, _TIF_NEED_RESCHED;
+       bnei    r5, preempt /* if non zero jump to resched */
+restore:
+#endif
+       VM_OFF /* MS: turn off MMU */
        tophys(r1,r1)
        lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
        lwi     r4, r1, PTO + PT_R4;
@@ -915,7 +917,7 @@ C_ENTRY(_debug_exception):
        swi     r11, r1, PTO+PT_R1; /* Store user SP.  */
        addi    r11, r0, 1;
        swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
-2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        /* Save away the syscall number.  */
        swi     r0, r1, PTO+PT_R0;
        tovirt(r1,r1)
@@ -935,8 +937,7 @@ dbtrap_call:        rtbd    r11, 0;
        bnei    r11, 2f;
 
        /* Get current task ptr into r11 */
-       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_NEED_RESCHED;
        beqi    r11, 5f;
@@ -949,8 +950,7 @@ dbtrap_call:        rtbd    r11, 0;
        /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */
 
        /* Maybe handle a signal */
-5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+5:     lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_SIGPENDING;
        beqi    r11, 1f;                /* Signals to handle, handle them */
@@ -966,16 +966,14 @@ dbtrap_call:      rtbd    r11, 0;
           (in a possibly modified form) after do_signal returns.  */
 
        la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
-       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
        addi  r7, r0, 0;        /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
-       nop;
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
 
 
 /* Finally, return to user state.  */
 1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
-       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
 
@@ -1007,7 +1005,7 @@ DBTRAP_return:            /* Make global symbol for debugging */
 
 ENTRY(_switch_to)
        /* prepare return value */
-       addk    r3, r0, r31
+       addk    r3, r0, CURRENT_TASK
 
        /* save registers in cpu_context */
        /* use r11 and r12, volatile registers, as temp register */
@@ -1051,10 +1049,10 @@ ENTRY(_switch_to)
        nop
        swi     r12, r11, CC_FSR
 
-       /* update r31, the current */
-       lwi     r31, r6, TI_TASK/* give me pointer to task which will be next */
+       /* update r31, the current-give me pointer to task which will be next */
+       lwi     CURRENT_TASK, r6, TI_TASK
        /* stored it to current_save too */
-       swi     r31, r0, PER_CPU(CURRENT_SAVE)
+       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE)
 
        /* get new process' cpu context and restore */
        /* give me start where start context of next task */
index 3091619..cb7815c 100644 (file)
@@ -99,8 +99,8 @@ no_fdt_arg:
        tophys(r4,r4)                   /* convert to phys address */
        ori     r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
 _copy_command_line:
-       lbu     r7, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */
-       sb      r7, r4, r6              /* addr[r4+r6]= r7*/
+       lbu     r2, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */
+       sb      r2, r4, r6              /* addr[r4+r6]= r7*/
        addik   r6, r6, 1               /* increment counting */
        bgtid   r3, _copy_command_line  /* loop for all entries       */
        addik   r3, r3, -1              /* descrement loop */
@@ -136,6 +136,11 @@ _invalidate:
        addik   r3, r3, -1
        /* sync */
 
+       /* Setup the kernel PID */
+       mts     rpid,r0                 /* Load the kernel PID */
+       nop
+       bri     4
+
        /*
         * We should still be executing code at physical address area
         * RAM_BASEADDR at this point. However, kernel code is at
@@ -146,10 +151,6 @@ _invalidate:
        addik   r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
        tophys(r4,r3)                   /* Load the kernel physical address */
 
-       mts     rpid,r0                 /* Load the kernel PID */
-       nop
-       bri     4
-
        /*
         * Configure and load two entries into TLB slots 0 and 1.
         * In case we are pinning TLBs, these are reserved in by the
index 0f06034..6f39e2c 100644 (file)
@@ -93,3 +93,18 @@ skip:
        }
        return 0;
 }
+
+/* MS: There is no any advance mapping mechanism. We are using simple 32bit
+  intc without any cascades or any connection that's why mapping is 1:1 */
+unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
+{
+       return hwirq;
+}
+EXPORT_SYMBOL_GPL(irq_create_mapping);
+
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                       u32 *intspec, unsigned int intsize)
+{
+       return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index bb8c4b9..f974ec7 100644 (file)
 #include <linux/io.h>
 #include <linux/bug.h>
 #include <linux/param.h>
+#include <linux/pci.h>
 #include <linux/cache.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
 #include <asm/cacheflush.h>
 #include <asm/entry.h>
 #include <asm/cpuinfo.h>
@@ -54,14 +57,10 @@ void __init setup_arch(char **cmdline_p)
 
        microblaze_cache_init();
 
-       invalidate_dcache();
-       enable_dcache();
-
-       invalidate_icache();
-       enable_icache();
-
        setup_memory();
 
+       xilinx_pci_init();
+
 #if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
        printk(KERN_NOTICE "Self modified code enable\n");
 #endif
@@ -188,3 +187,37 @@ static int microblaze_debugfs_init(void)
 }
 arch_initcall(microblaze_debugfs_init);
 #endif
+
+static int dflt_bus_notify(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       struct device *dev = data;
+
+       /* We are only intereted in device addition */
+       if (action != BUS_NOTIFY_ADD_DEVICE)
+               return 0;
+
+       set_dma_ops(dev, &dma_direct_ops);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block dflt_plat_bus_notifier = {
+       .notifier_call = dflt_bus_notify,
+       .priority = INT_MAX,
+};
+
+static struct notifier_block dflt_of_bus_notifier = {
+       .notifier_call = dflt_bus_notify,
+       .priority = INT_MAX,
+};
+
+static int __init setup_bus_notifier(void)
+{
+       bus_register_notifier(&platform_bus_type, &dflt_plat_bus_notifier);
+       bus_register_notifier(&of_platform_bus_type, &dflt_of_bus_notifier);
+
+       return 0;
+}
+
+arch_initcall(setup_bus_notifier);
index 6c8a924..09c49ed 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile
 #
 
-obj-y := init.o
+obj-y := consistent.o init.o
 
 obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c
new file mode 100644 (file)
index 0000000..a9b443e
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Microblaze support for cache consistent memory.
+ * Copyright (C) 2010 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2010 PetaLogix
+ * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au>
+ *
+ * Based on PowerPC version derived from arch/arm/mm/consistent.c
+ * Copyright (C) 2001 Dan Malek (dmalek@jlc.net)
+ * Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <asm/pgalloc.h>
+#include <linux/io.h>
+#include <linux/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/mmu.h>
+#include <linux/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cpuinfo.h>
+
+#ifndef CONFIG_MMU
+
+/* I have to use dcache values because I can't relate on ram size */
+#define UNCACHED_SHADOW_MASK (cpuinfo.dcache_high - cpuinfo.dcache_base + 1)
+
+/*
+ * Consistent memory allocators. Used for DMA devices that want to
+ * share uncached memory with the processor core.
+ * My crufty no-MMU approach is simple. In the HW platform we can optionally
+ * mirror the DDR up above the processor cacheable region.  So, memory accessed
+ * in this mirror region will not be cached.  It's alloced from the same
+ * pool as normal memory, but the handle we return is shifted up into the
+ * uncached region.  This will no doubt cause big problems if memory allocated
+ * here is not also freed properly. -- JW
+ */
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+{
+       struct page *page, *end, *free;
+       unsigned long order;
+       void *ret, *virt;
+
+       if (in_interrupt())
+               BUG();
+
+       size = PAGE_ALIGN(size);
+       order = get_order(size);
+
+       page = alloc_pages(gfp, order);
+       if (!page)
+               goto no_page;
+
+       /* We could do with a page_to_phys and page_to_bus here. */
+       virt = page_address(page);
+       ret = ioremap(virt_to_phys(virt), size);
+       if (!ret)
+               goto no_remap;
+
+       /*
+        * Here's the magic!  Note if the uncached shadow is not implemented,
+        * it's up to the calling code to also test that condition and make
+        * other arranegments, such as manually flushing the cache and so on.
+        */
+#ifdef CONFIG_XILINX_UNCACHED_SHADOW
+       ret = (void *)((unsigned) ret | UNCACHED_SHADOW_MASK);
+#endif
+       /* dma_handle is same as physical (shadowed) address */
+       *dma_handle = (dma_addr_t)ret;
+
+       /*
+        * free wasted pages.  We skip the first page since we know
+        * that it will have count = 1 and won't require freeing.
+        * We also mark the pages in use as reserved so that
+        * remap_page_range works.
+        */
+       page = virt_to_page(virt);
+       free = page + (size >> PAGE_SHIFT);
+       end  = page + (1 << order);
+
+       for (; page < end; page++) {
+               init_page_count(page);
+               if (page >= free)
+                       __free_page(page);
+               else
+                       SetPageReserved(page);
+       }
+
+       return ret;
+no_remap:
+       __free_pages(page, order);
+no_page:
+       return NULL;
+}
+
+#else
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+{
+       int order, err, i;
+       unsigned long page, va, flags;
+       phys_addr_t pa;
+       struct vm_struct *area;
+       void     *ret;
+
+       if (in_interrupt())
+               BUG();
+
+       /* Only allocate page size areas. */
+       size = PAGE_ALIGN(size);
+       order = get_order(size);
+
+       page = __get_free_pages(gfp, order);
+       if (!page) {
+               BUG();
+               return NULL;
+       }
+
+       /*
+        * we need to ensure that there are no cachelines in use,
+        * or worse dirty in this area.
+        */
+       flush_dcache_range(virt_to_phys(page), virt_to_phys(page) + size);
+
+       /* Allocate some common virtual space to map the new pages. */
+       area = get_vm_area(size, VM_ALLOC);
+       if (area == NULL) {
+               free_pages(page, order);
+               return NULL;
+       }
+       va = (unsigned long) area->addr;
+       ret = (void *)va;
+
+       /* This gives us the real physical address of the first page. */
+       *dma_handle = pa = virt_to_bus((void *)page);
+
+       /* MS: This is the whole magic - use cache inhibit pages */
+       flags = _PAGE_KERNEL | _PAGE_NO_CACHE;
+
+       /*
+        * Set refcount=1 on all pages in an order>0
+        * allocation so that vfree() will actually
+        * free all pages that were allocated.
+        */
+       if (order > 0) {
+               struct page *rpage = virt_to_page(page);
+               for (i = 1; i < (1 << order); i++)
+                       init_page_count(rpage+i);
+       }
+
+       err = 0;
+       for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+               err = map_page(va+i, pa+i, flags);
+
+       if (err) {
+               vfree((void *)va);
+               return NULL;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_MMU */
+EXPORT_SYMBOL(consistent_alloc);
+
+/*
+ * free page(s) as defined by the above mapping.
+ */
+void consistent_free(void *vaddr)
+{
+       if (in_interrupt())
+               BUG();
+
+       /* Clear SHADOW_MASK bit in address, and free as per usual */
+#ifdef CONFIG_XILINX_UNCACHED_SHADOW
+       vaddr = (void *)((unsigned)vaddr & ~UNCACHED_SHADOW_MASK);
+#endif
+       vfree(vaddr);
+}
+EXPORT_SYMBOL(consistent_free);
+
+/*
+ * make an area consistent.
+ */
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+       unsigned long start;
+       unsigned long end;
+
+       start = (unsigned long)vaddr;
+
+       /* Convert start address back down to unshadowed memory region */
+#ifdef CONFIG_XILINX_UNCACHED_SHADOW
+       start &= ~UNCACHED_SHADOW_MASK;
+#endif
+       end = start + size;
+
+       switch (direction) {
+       case PCI_DMA_NONE:
+               BUG();
+       case PCI_DMA_FROMDEVICE:        /* invalidate only */
+               flush_dcache_range(start, end);
+               break;
+       case PCI_DMA_TODEVICE:          /* writeback only */
+               flush_dcache_range(start, end);
+               break;
+       case PCI_DMA_BIDIRECTIONAL:     /* writeback and invalidate */
+               flush_dcache_range(start, end);
+               break;
+       }
+}
+EXPORT_SYMBOL(consistent_sync);
+
+/*
+ * consistent_sync_page makes memory consistent. identical
+ * to consistent_sync, but takes a struct page instead of a
+ * virtual address
+ */
+void consistent_sync_page(struct page *page, unsigned long offset,
+       size_t size, int direction)
+{
+       unsigned long start = (unsigned long)page_address(page) + offset;
+       consistent_sync((void *)start, size, direction);
+}
+EXPORT_SYMBOL(consistent_sync_page);
index a57cedf..1608e2e 100644 (file)
@@ -23,6 +23,9 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
+/* Use for MMU and noMMU because of PCI generic code */
+int mem_init_done;
+
 #ifndef CONFIG_MMU
 unsigned int __page_offset;
 EXPORT_SYMBOL(__page_offset);
@@ -30,7 +33,6 @@ EXPORT_SYMBOL(__page_offset);
 #else
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-int mem_init_done;
 static int init_bootmem_done;
 #endif /* CONFIG_MMU */
 
@@ -193,12 +195,6 @@ void free_initmem(void)
                        (unsigned long)(&__init_end));
 }
 
-/* FIXME from arch/powerpc/mm/mem.c*/
-void show_mem(void)
-{
-       printk(KERN_NOTICE "%s\n", __func__);
-}
-
 void __init mem_init(void)
 {
        high_memory = (void *)__va(memory_end);
@@ -208,9 +204,7 @@ void __init mem_init(void)
        printk(KERN_INFO "Memory: %luk/%luk available\n",
               nr_free_pages() << (PAGE_SHIFT-10),
               num_physpages << (PAGE_SHIFT-10));
-#ifdef CONFIG_MMU
        mem_init_done = 1;
-#endif
 }
 
 #ifndef CONFIG_MMU
@@ -222,6 +216,10 @@ int ___range_ok(unsigned long addr, unsigned long size)
 }
 EXPORT_SYMBOL(___range_ok);
 
+int page_is_ram(unsigned long pfn)
+{
+       return __range_ok(pfn, 0);
+}
 #else
 int page_is_ram(unsigned long pfn)
 {
@@ -349,4 +347,27 @@ void __init *early_get_page(void)
        }
        return p;
 }
+
 #endif /* CONFIG_MMU */
+
+void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
+{
+       if (mem_init_done)
+               return kmalloc(size, mask);
+       else
+               return alloc_bootmem(size);
+}
+
+void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
+{
+       void *p;
+
+       if (mem_init_done)
+               p = kzalloc(size, mask);
+       else {
+               p = alloc_bootmem(size);
+               if (p)
+                       memset(p, 0, size);
+       }
+       return p;
+}
index 2820081..63a6fd0 100644 (file)
@@ -103,7 +103,7 @@ static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
                area = get_vm_area(size, VM_IOREMAP);
                if (area == NULL)
                        return NULL;
-               v = VMALLOC_VMADDR(area->addr);
+               v = (unsigned long) area->addr;
        } else {
                v = (ioremap_bot -= size);
        }
diff --git a/arch/microblaze/pci/Makefile b/arch/microblaze/pci/Makefile
new file mode 100644 (file)
index 0000000..9889cc2
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile
+#
+
+obj-$(CONFIG_PCI)              += pci_32.o pci-common.o indirect_pci.o iomap.o
+obj-$(CONFIG_PCI_XILINX)       += xilinx_pci.o
diff --git a/arch/microblaze/pci/indirect_pci.c b/arch/microblaze/pci/indirect_pci.c
new file mode 100644 (file)
index 0000000..25f18f0
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+static int
+indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                    int len, u32 *val)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       volatile void __iomem *cfg_data;
+       u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
+               if (bus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc; /* Only 3 bits for function */
+
+       if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+               out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+       else
+               out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */
+       switch (len) {
+       case 1:
+               *val = in_8(cfg_data);
+               break;
+       case 2:
+               *val = in_le16(cfg_data);
+               break;
+       default:
+               *val = in_le32(cfg_data);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                     int len, u32 val)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       volatile void __iomem *cfg_data;
+       u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
+               if (bus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc;
+
+       if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+               out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+       else
+               out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+
+       /* surpress setting of PCI_PRIMARY_BUS */
+       if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+               if ((offset == PCI_PRIMARY_BUS) &&
+                       (bus->number == hose->first_busno))
+                       val &= 0xffffff00;
+
+       /* Workaround for PCI_28 Errata in 440EPx/GRx */
+       if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) &&
+                       offset == PCI_CACHE_LINE_SIZE) {
+               val = 0;
+       }
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       cfg_data = hose->cfg_data + (offset & 3);
+       switch (len) {
+       case 1:
+               out_8(cfg_data, val);
+               break;
+       case 2:
+               out_le16(cfg_data, val);
+               break;
+       default:
+               out_le32(cfg_data, val);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops = {
+       .read = indirect_read_config,
+       .write = indirect_write_config,
+};
+
+void __init
+setup_indirect_pci(struct pci_controller *hose,
+                  resource_size_t cfg_addr,
+                  resource_size_t cfg_data, u32 flags)
+{
+       resource_size_t base = cfg_addr & PAGE_MASK;
+       void __iomem *mbase;
+
+       mbase = ioremap(base, PAGE_SIZE);
+       hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
+       if ((cfg_data & PAGE_MASK) != base)
+               mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+       hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
+       hose->ops = &indirect_pci_ops;
+       hose->indirect_type = flags;
+}
diff --git a/arch/microblaze/pci/iomap.c b/arch/microblaze/pci/iomap.c
new file mode 100644 (file)
index 0000000..3fbf16f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ppc64 "iomap" interface implementation.
+ *
+ * (C) Copyright 2004 Linus Torvalds
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+       resource_size_t start = pci_resource_start(dev, bar);
+       resource_size_t len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len)
+               return NULL;
+       if (max && len > max)
+               len = max;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM)
+               return ioremap(start, len);
+       /* What? */
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       if (isa_vaddr_is_ioport(addr))
+               return;
+       if (pcibios_vaddr_is_ioport(addr))
+               return;
+       iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
new file mode 100644 (file)
index 0000000..0be3435
--- /dev/null
@@ -0,0 +1,1642 @@
+/*
+ * Contains common pci routines for ALL ppc platform
+ * (based on pci_32.c and pci_64.c)
+ *
+ * Port for PPC64 David Engebretsen, IBM Corp.
+ * Contains common pci routines for ppc64 platform, pSeries and iSeries brands.
+ *
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ *   Rework, based on alpha PCI code.
+ *
+ * Common pmac/prep/chrp pci routines. -- Cort
+ *
+ * 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/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/syscalls.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/byteorder.h>
+
+static DEFINE_SPINLOCK(hose_spinlock);
+LIST_HEAD(hose_list);
+
+/* XXX kill that some day ... */
+static int global_phb_number;          /* Global phb counter */
+
+/* ISA Memory physical address */
+resource_size_t isa_mem_base;
+
+/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
+unsigned int pci_flags;
+
+static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
+
+void set_pci_dma_ops(struct dma_map_ops *dma_ops)
+{
+       pci_dma_ops = dma_ops;
+}
+
+struct dma_map_ops *get_pci_dma_ops(void)
+{
+       return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
+int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return dma_set_mask(&dev->dev, mask);
+}
+
+int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       int rc;
+
+       rc = dma_set_mask(&dev->dev, mask);
+       dev->dev.coherent_dma_mask = dev->dma_mask;
+
+       return rc;
+}
+
+struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
+{
+       struct pci_controller *phb;
+
+       phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
+       if (!phb)
+               return NULL;
+       spin_lock(&hose_spinlock);
+       phb->global_number = global_phb_number++;
+       list_add_tail(&phb->list_node, &hose_list);
+       spin_unlock(&hose_spinlock);
+       phb->dn = dev;
+       phb->is_dynamic = mem_init_done;
+       return phb;
+}
+
+void pcibios_free_controller(struct pci_controller *phb)
+{
+       spin_lock(&hose_spinlock);
+       list_del(&phb->list_node);
+       spin_unlock(&hose_spinlock);
+
+       if (phb->is_dynamic)
+               kfree(phb);
+}
+
+static resource_size_t pcibios_io_size(const struct pci_controller *hose)
+{
+       return hose->io_resource.end - hose->io_resource.start + 1;
+}
+
+int pcibios_vaddr_is_ioport(void __iomem *address)
+{
+       int ret = 0;
+       struct pci_controller *hose;
+       resource_size_t size;
+
+       spin_lock(&hose_spinlock);
+       list_for_each_entry(hose, &hose_list, list_node) {
+               size = pcibios_io_size(hose);
+               if (address >= hose->io_base_virt &&
+                   address < (hose->io_base_virt + size)) {
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock(&hose_spinlock);
+       return ret;
+}
+
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose;
+       resource_size_t size;
+       unsigned long ret = ~0;
+
+       spin_lock(&hose_spinlock);
+       list_for_each_entry(hose, &hose_list, list_node) {
+               size = pcibios_io_size(hose);
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       ret = base + (address - hose->io_base_phys);
+                       break;
+               }
+       }
+       spin_unlock(&hose_spinlock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
+/*
+ * Return the domain number for this bus.
+ */
+int pci_domain_nr(struct pci_bus *bus)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+
+       return hose->global_number;
+}
+EXPORT_SYMBOL(pci_domain_nr);
+
+/* This routine is meant to be used early during boot, when the
+ * PCI bus numbers have not yet been assigned, and you need to
+ * issue PCI config cycles to an OF device.
+ * It could also be used to "fix" RTAS config cycles if you want
+ * to set pci_assign_all_buses to 1 and still use RTAS for PCI
+ * config cycles.
+ */
+struct pci_controller *pci_find_hose_for_OF_device(struct device_node *node)
+{
+       while (node) {
+               struct pci_controller *hose, *tmp;
+               list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+                       if (hose->dn == node)
+                               return hose;
+               node = node->parent;
+       }
+       return NULL;
+}
+
+static ssize_t pci_show_devspec(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev;
+       struct device_node *np;
+
+       pdev = to_pci_dev(dev);
+       np = pci_device_to_OF_node(pdev);
+       if (np == NULL || np->full_name == NULL)
+               return 0;
+       return sprintf(buf, "%s", np->full_name);
+}
+static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
+
+/* Add sysfs properties */
+int pcibios_add_platform_entries(struct pci_dev *pdev)
+{
+       return device_create_file(&pdev->dev, &dev_attr_devspec);
+}
+
+char __devinit *pcibios_setup(char *str)
+{
+       return str;
+}
+
+/*
+ * Reads the interrupt pin to determine if interrupt is use by card.
+ * If the interrupt is used, then gets the interrupt line from the
+ * openfirmware and sets it in the pci_dev and pci_config line.
+ */
+int pci_read_irq_line(struct pci_dev *pci_dev)
+{
+       struct of_irq oirq;
+       unsigned int virq;
+
+       /* The current device-tree that iSeries generates from the HV
+        * PCI informations doesn't contain proper interrupt routing,
+        * and all the fallback would do is print out crap, so we
+        * don't attempt to resolve the interrupts here at all, some
+        * iSeries specific fixup does it.
+        *
+        * In the long run, we will hopefully fix the generated device-tree
+        * instead.
+        */
+       pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
+
+#ifdef DEBUG
+       memset(&oirq, 0xff, sizeof(oirq));
+#endif
+       /* Try to get a mapping from the device-tree */
+       if (of_irq_map_pci(pci_dev, &oirq)) {
+               u8 line, pin;
+
+               /* If that fails, lets fallback to what is in the config
+                * space and map that through the default controller. We
+                * also set the type to level low since that's what PCI
+                * interrupts are. If your platform does differently, then
+                * either provide a proper interrupt tree or don't use this
+                * function.
+                */
+               if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
+                       return -1;
+               if (pin == 0)
+                       return -1;
+               if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
+                   line == 0xff || line == 0) {
+                       return -1;
+               }
+               pr_debug(" No map ! Using line %d (pin %d) from PCI config\n",
+                        line, pin);
+
+               virq = irq_create_mapping(NULL, line);
+               if (virq != NO_IRQ)
+                       set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+       } else {
+               pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
+                        oirq.size, oirq.specifier[0], oirq.specifier[1],
+                        oirq.controller ? oirq.controller->full_name :
+                        "<default>");
+
+               virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+                                            oirq.size);
+       }
+       if (virq == NO_IRQ) {
+               pr_debug(" Failed to map !\n");
+               return -1;
+       }
+
+       pr_debug(" Mapped to linux irq %d\n", virq);
+
+       pci_dev->irq = virq;
+
+       return 0;
+}
+EXPORT_SYMBOL(pci_read_irq_line);
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ *  -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap.  They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+                                              resource_size_t *offset,
+                                              enum pci_mmap_state mmap_state)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       unsigned long io_offset = 0;
+       int i, res_bit;
+
+       if (hose == 0)
+               return NULL;            /* should never happen */
+
+       /* If memory, add on the PCI bridge address offset */
+       if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
+               *offset += hose->pci_mem_offset;
+#endif
+               res_bit = IORESOURCE_MEM;
+       } else {
+               io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               *offset += io_offset;
+               res_bit = IORESOURCE_IO;
+       }
+
+       /*
+        * Check that the offset requested corresponds to one of the
+        * resources of the device.
+        */
+       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+               struct resource *rp = &dev->resource[i];
+               int flags = rp->flags;
+
+               /* treat ROM as memory (should be already) */
+               if (i == PCI_ROM_RESOURCE)
+                       flags |= IORESOURCE_MEM;
+
+               /* Active and same type? */
+               if ((flags & res_bit) == 0)
+                       continue;
+
+               /* In the range of this resource? */
+               if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+                       continue;
+
+               /* found it! construct the final physical address */
+               if (mmap_state == pci_mmap_io)
+                       *offset += hose->io_base_phys - io_offset;
+               return rp;
+       }
+
+       return NULL;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+                                     pgprot_t protection,
+                                     enum pci_mmap_state mmap_state,
+                                     int write_combine)
+{
+       pgprot_t prot = protection;
+
+       /* Write combine is always 0 on non-memory space mappings. On
+        * memory space, if the user didn't pass 1, we check for a
+        * "prefetchable" resource. This is a bit hackish, but we use
+        * this to workaround the inability of /sysfs to provide a write
+        * combine bit
+        */
+       if (mmap_state != pci_mmap_mem)
+               write_combine = 0;
+       else if (write_combine == 0) {
+               if (rp->flags & IORESOURCE_PREFETCH)
+                       write_combine = 1;
+       }
+
+       return pgprot_noncached(prot);
+}
+
+/*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+                                 unsigned long pfn,
+                                 unsigned long size,
+                                 pgprot_t prot)
+{
+       struct pci_dev *pdev = NULL;
+       struct resource *found = NULL;
+       resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
+       int i;
+
+       if (page_is_ram(pfn))
+               return prot;
+
+       prot = pgprot_noncached(prot);
+       for_each_pci_dev(pdev) {
+               for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+                       struct resource *rp = &pdev->resource[i];
+                       int flags = rp->flags;
+
+                       /* Active and same type? */
+                       if ((flags & IORESOURCE_MEM) == 0)
+                               continue;
+                       /* In the range of this resource? */
+                       if (offset < (rp->start & PAGE_MASK) ||
+                           offset > rp->end)
+                               continue;
+                       found = rp;
+                       break;
+               }
+               if (found)
+                       break;
+       }
+       if (found) {
+               if (found->flags & IORESOURCE_PREFETCH)
+                       prot = pgprot_noncached_wc(prot);
+               pci_dev_put(pdev);
+       }
+
+       pr_debug("PCI: Non-PCI map for %llx, prot: %lx\n",
+                (unsigned long long)offset, pgprot_val(prot));
+
+       return prot;
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state, int write_combine)
+{
+       resource_size_t offset =
+               ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
+       struct resource *rp;
+       int ret;
+
+       rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+       if (rp == NULL)
+               return -EINVAL;
+
+       vma->vm_pgoff = offset >> PAGE_SHIFT;
+       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+                                                 vma->vm_page_prot,
+                                                 mmap_state, write_combine);
+
+       ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+       return ret;
+}
+
+/* This provides legacy IO read access on a bus */
+int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
+{
+       unsigned long offset;
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       struct resource *rp = &hose->io_resource;
+       void __iomem *addr;
+
+       /* Check if port can be supported by that bus. We only check
+        * the ranges of the PHB though, not the bus itself as the rules
+        * for forwarding legacy cycles down bridges are not our problem
+        * here. So if the host bridge supports it, we do it.
+        */
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       offset += port;
+
+       if (!(rp->flags & IORESOURCE_IO))
+               return -ENXIO;
+       if (offset < rp->start || (offset + size) > rp->end)
+               return -ENXIO;
+       addr = hose->io_base_virt + port;
+
+       switch (size) {
+       case 1:
+               *((u8 *)val) = in_8(addr);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               *((u16 *)val) = in_le16(addr);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               *((u32 *)val) = in_le32(addr);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+/* This provides legacy IO write access on a bus */
+int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
+{
+       unsigned long offset;
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       struct resource *rp = &hose->io_resource;
+       void __iomem *addr;
+
+       /* Check if port can be supported by that bus. We only check
+        * the ranges of the PHB though, not the bus itself as the rules
+        * for forwarding legacy cycles down bridges are not our problem
+        * here. So if the host bridge supports it, we do it.
+        */
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       offset += port;
+
+       if (!(rp->flags & IORESOURCE_IO))
+               return -ENXIO;
+       if (offset < rp->start || (offset + size) > rp->end)
+               return -ENXIO;
+       addr = hose->io_base_virt + port;
+
+       /* WARNING: The generic code is idiotic. It gets passed a pointer
+        * to what can be a 1, 2 or 4 byte quantity and always reads that
+        * as a u32, which means that we have to correct the location of
+        * the data read within those 32 bits for size 1 and 2
+        */
+       switch (size) {
+       case 1:
+               out_8(addr, val >> 24);
+               return 1;
+       case 2:
+               if (port & 1)
+                       return -EINVAL;
+               out_le16(addr, val >> 16);
+               return 2;
+       case 4:
+               if (port & 3)
+                       return -EINVAL;
+               out_le32(addr, val);
+               return 4;
+       }
+       return -EINVAL;
+}
+
+/* This provides legacy IO or memory mmap access on a bus */
+int pci_mmap_legacy_page_range(struct pci_bus *bus,
+                              struct vm_area_struct *vma,
+                              enum pci_mmap_state mmap_state)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       resource_size_t offset =
+               ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
+       resource_size_t size = vma->vm_end - vma->vm_start;
+       struct resource *rp;
+
+       pr_debug("pci_mmap_legacy_page_range(%04x:%02x, %s @%llx..%llx)\n",
+                pci_domain_nr(bus), bus->number,
+                mmap_state == pci_mmap_mem ? "MEM" : "IO",
+                (unsigned long long)offset,
+                (unsigned long long)(offset + size - 1));
+
+       if (mmap_state == pci_mmap_mem) {
+               /* Hack alert !
+                *
+                * Because X is lame and can fail starting if it gets an error
+                * trying to mmap legacy_mem (instead of just moving on without
+                * legacy memory access) we fake it here by giving it anonymous
+                * memory, effectively behaving just like /dev/zero
+                */
+               if ((offset + size) > hose->isa_mem_size) {
+#ifdef CONFIG_MMU
+                       printk(KERN_DEBUG
+                               "Process %s (pid:%d) mapped non-existing PCI"
+                               "legacy memory for 0%04x:%02x\n",
+                               current->comm, current->pid, pci_domain_nr(bus),
+                                                               bus->number);
+#endif
+                       if (vma->vm_flags & VM_SHARED)
+                               return shmem_zero_setup(vma);
+                       return 0;
+               }
+               offset += hose->isa_mem_phys;
+       } else {
+               unsigned long io_offset = (unsigned long)hose->io_base_virt - \
+                                                               _IO_BASE;
+               unsigned long roffset = offset + io_offset;
+               rp = &hose->io_resource;
+               if (!(rp->flags & IORESOURCE_IO))
+                       return -ENXIO;
+               if (roffset < rp->start || (roffset + size) > rp->end)
+                       return -ENXIO;
+               offset += hose->io_base_phys;
+       }
+       pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset);
+
+       vma->vm_pgoff = offset >> PAGE_SHIFT;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         resource_size_t *start, resource_size_t *end)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       resource_size_t offset = 0;
+
+       if (hose == NULL)
+               return;
+
+       if (rsrc->flags & IORESOURCE_IO)
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
+
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
+}
+
+/**
+ * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
+ * @hose: newly allocated pci_controller to be setup
+ * @dev: device node of the host bridge
+ * @primary: set if primary bus (32 bits only, soon to be deprecated)
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping of a pci controller based on its
+ * content.
+ *
+ * Life would be boring if it wasn't for a few issues that we have to deal
+ * with here:
+ *
+ *   - We can only cope with one IO space range and up to 3 Memory space
+ *     ranges. However, some machines (thanks Apple !) tend to split their
+ *     space into lots of small contiguous ranges. So we have to coalesce.
+ *
+ *   - We can only cope with all memory ranges having the same offset
+ *     between CPU addresses and PCI addresses. Unfortunately, some bridges
+ *     are setup for a large 1:1 mapping along with a small "window" which
+ *     maps PCI address 0 to some arbitrary high address of the CPU space in
+ *     order to give access to the ISA memory hole.
+ *     The way out of here that I've chosen for now is to always set the
+ *     offset based on the first resource found, then override it if we
+ *     have a different offset and the previous was set by an ISA hole.
+ *
+ *   - Some busses have IO space not starting at 0, which causes trouble with
+ *     the way we do our IO resource renumbering. The code somewhat deals with
+ *     it for 64 bits but I would expect problems on 32 bits.
+ *
+ *   - Some 32 bits platforms such as 4xx can have physical space larger than
+ *     32 bits so we need to use 64 bits values for the parsing
+ */
+void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
+                                           struct device_node *dev,
+                                           int primary)
+{
+       const u32 *ranges;
+       int rlen;
+       int pna = of_n_addr_cells(dev);
+       int np = pna + 5;
+       int memno = 0, isa_hole = -1;
+       u32 pci_space;
+       unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
+       unsigned long long isa_mb = 0;
+       struct resource *res;
+
+       printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
+              dev->full_name, primary ? "(primary)" : "");
+
+       /* Get ranges property */
+       ranges = of_get_property(dev, "ranges", &rlen);
+       if (ranges == NULL)
+               return;
+
+       /* Parse it */
+       pr_debug("Parsing ranges property...\n");
+       while ((rlen -= np * 4) >= 0) {
+               /* Read next ranges element */
+               pci_space = ranges[0];
+               pci_addr = of_read_number(ranges + 1, 2);
+               cpu_addr = of_translate_address(dev, ranges + 3);
+               size = of_read_number(ranges + pna + 3, 2);
+
+               pr_debug("pci_space: 0x%08x pci_addr:0x%016llx "
+                               "cpu_addr:0x%016llx size:0x%016llx\n",
+                                       pci_space, pci_addr, cpu_addr, size);
+
+               ranges += np;
+
+               /* If we failed translation or got a zero-sized region
+                * (some FW try to feed us with non sensical zero sized regions
+                * such as power3 which look like some kind of attempt
+                * at exposing the VGA memory hole)
+                */
+               if (cpu_addr == OF_BAD_ADDR || size == 0)
+                       continue;
+
+               /* Now consume following elements while they are contiguous */
+               for (; rlen >= np * sizeof(u32);
+                    ranges += np, rlen -= np * 4) {
+                       if (ranges[0] != pci_space)
+                               break;
+                       pci_next = of_read_number(ranges + 1, 2);
+                       cpu_next = of_translate_address(dev, ranges + 3);
+                       if (pci_next != pci_addr + size ||
+                           cpu_next != cpu_addr + size)
+                               break;
+                       size += of_read_number(ranges + pna + 3, 2);
+               }
+
+               /* Act based on address space type */
+               res = NULL;
+               switch ((pci_space >> 24) & 0x3) {
+               case 1:         /* PCI IO space */
+                       printk(KERN_INFO
+                              "  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+                              cpu_addr, cpu_addr + size - 1, pci_addr);
+
+                       /* We support only one IO range */
+                       if (hose->pci_io_size) {
+                               printk(KERN_INFO
+                                      " \\--> Skipped (too many) !\n");
+                               continue;
+                       }
+                       /* On 32 bits, limit I/O space to 16MB */
+                       if (size > 0x01000000)
+                               size = 0x01000000;
+
+                       /* 32 bits needs to map IOs here */
+                       hose->io_base_virt = ioremap(cpu_addr, size);
+
+                       /* Expect trouble if pci_addr is not 0 */
+                       if (primary)
+                               isa_io_base =
+                                       (unsigned long)hose->io_base_virt;
+                       /* pci_io_size and io_base_phys always represent IO
+                        * space starting at 0 so we factor in pci_addr
+                        */
+                       hose->pci_io_size = pci_addr + size;
+                       hose->io_base_phys = cpu_addr - pci_addr;
+
+                       /* Build resource */
+                       res = &hose->io_resource;
+                       res->flags = IORESOURCE_IO;
+                       res->start = pci_addr;
+                       break;
+               case 2:         /* PCI Memory space */
+               case 3:         /* PCI 64 bits Memory space */
+                       printk(KERN_INFO
+                              " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
+                              cpu_addr, cpu_addr + size - 1, pci_addr,
+                              (pci_space & 0x40000000) ? "Prefetch" : "");
+
+                       /* We support only 3 memory ranges */
+                       if (memno >= 3) {
+                               printk(KERN_INFO
+                                      " \\--> Skipped (too many) !\n");
+                               continue;
+                       }
+                       /* Handles ISA memory hole space here */
+                       if (pci_addr == 0) {
+                               isa_mb = cpu_addr;
+                               isa_hole = memno;
+                               if (primary || isa_mem_base == 0)
+                                       isa_mem_base = cpu_addr;
+                               hose->isa_mem_phys = cpu_addr;
+                               hose->isa_mem_size = size;
+                       }
+
+                       /* We get the PCI/Mem offset from the first range or
+                        * the, current one if the offset came from an ISA
+                        * hole. If they don't match, bugger.
+                        */
+                       if (memno == 0 ||
+                           (isa_hole >= 0 && pci_addr != 0 &&
+                            hose->pci_mem_offset == isa_mb))
+                               hose->pci_mem_offset = cpu_addr - pci_addr;
+                       else if (pci_addr != 0 &&
+                                hose->pci_mem_offset != cpu_addr - pci_addr) {
+                               printk(KERN_INFO
+                                      " \\--> Skipped (offset mismatch) !\n");
+                               continue;
+                       }
+
+                       /* Build resource */
+                       res = &hose->mem_resources[memno++];
+                       res->flags = IORESOURCE_MEM;
+                       if (pci_space & 0x40000000)
+                               res->flags |= IORESOURCE_PREFETCH;
+                       res->start = cpu_addr;
+                       break;
+               }
+               if (res != NULL) {
+                       res->name = dev->full_name;
+                       res->end = res->start + size - 1;
+                       res->parent = NULL;
+                       res->sibling = NULL;
+                       res->child = NULL;
+               }
+       }
+
+       /* If there's an ISA hole and the pci_mem_offset is -not- matching
+        * the ISA hole offset, then we need to remove the ISA hole from
+        * the resource list for that brige
+        */
+       if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
+               unsigned int next = isa_hole + 1;
+               printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
+               if (next < memno)
+                       memmove(&hose->mem_resources[isa_hole],
+                               &hose->mem_resources[next],
+                               sizeof(struct resource) * (memno - next));
+               hose->mem_resources[--memno].flags = 0;
+       }
+}
+
+/* Decide whether to display the domain number in /proc */
+int pci_proc_domain(struct pci_bus *bus)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+
+       if (!(pci_flags & PCI_ENABLE_PROC_DOMAINS))
+               return 0;
+       if (pci_flags & PCI_COMPAT_DOMAIN_0)
+               return hose->global_number != 0;
+       return 1;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                            struct resource *res)
+{
+       resource_size_t offset = 0, mask = (resource_size_t)-1;
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+
+       if (!hose)
+               return;
+       if (res->flags & IORESOURCE_IO) {
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               mask = 0xffffffffu;
+       } else if (res->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+
+       region->start = (res->start - offset) & mask;
+       region->end = (res->end - offset) & mask;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                            struct pci_bus_region *region)
+{
+       resource_size_t offset = 0, mask = (resource_size_t)-1;
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+
+       if (!hose)
+               return;
+       if (res->flags & IORESOURCE_IO) {
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               mask = 0xffffffffu;
+       } else if (res->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+       res->start = (region->start + offset) & mask;
+       res->end = (region->end + offset) & mask;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
+/* Fixup a bus resource into a linux resource */
+static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       resource_size_t offset = 0, mask = (resource_size_t)-1;
+
+       if (res->flags & IORESOURCE_IO) {
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               mask = 0xffffffffu;
+       } else if (res->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+
+       res->start = (res->start + offset) & mask;
+       res->end = (res->end + offset) & mask;
+}
+
+/* This header fixup will do the resource fixup for all devices as they are
+ * probed, but not for bridge ranges
+ */
+static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       int i;
+
+       if (!hose) {
+               printk(KERN_ERR "No host bridge for PCI dev %s !\n",
+                      pci_name(dev));
+               return;
+       }
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               struct resource *res = dev->resource + i;
+               if (!res->flags)
+                       continue;
+               /* On platforms that have PCI_PROBE_ONLY set, we don't
+                * consider 0 as an unassigned BAR value. It's technically
+                * a valid value, but linux doesn't like it... so when we can
+                * re-assign things, we do so, but if we can't, we keep it
+                * around and hope for the best...
+                */
+               if (res->start == 0 && !(pci_flags & PCI_PROBE_ONLY)) {
+                       pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \
+                                                       "is unassigned\n",
+                                pci_name(dev), i,
+                                (unsigned long long)res->start,
+                                (unsigned long long)res->end,
+                                (unsigned int)res->flags);
+                       res->end -= res->start;
+                       res->start = 0;
+                       res->flags |= IORESOURCE_UNSET;
+                       continue;
+               }
+
+               pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+                        pci_name(dev), i,
+                        (unsigned long long)res->start,\
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags);
+
+               fixup_resource(res, dev);
+
+               pr_debug("PCI:%s            %016llx-%016llx\n",
+                        pci_name(dev),
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
+
+/* This function tries to figure out if a bridge resource has been initialized
+ * by the firmware or not. It doesn't have to be absolutely bullet proof, but
+ * things go more smoothly when it gets it right. It should covers cases such
+ * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
+ */
+static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+                                                          struct resource *res)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       struct pci_dev *dev = bus->self;
+       resource_size_t offset;
+       u16 command;
+       int i;
+
+       /* We don't do anything if PCI_PROBE_ONLY is set */
+       if (pci_flags & PCI_PROBE_ONLY)
+               return 0;
+
+       /* Job is a bit different between memory and IO */
+       if (res->flags & IORESOURCE_MEM) {
+               /* If the BAR is non-0 (res != pci_mem_offset) then it's
+                * probably been initialized by somebody
+                */
+               if (res->start != hose->pci_mem_offset)
+                       return 0;
+
+               /* The BAR is 0, let's check if memory decoding is enabled on
+                * the bridge. If not, we consider it unassigned
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if ((command & PCI_COMMAND_MEMORY) == 0)
+                       return 1;
+
+               /* Memory decoding is enabled and the BAR is 0. If any of
+                * the bridge resources covers that starting address (0 then
+                * it's good enough for us for memory
+                */
+               for (i = 0; i < 3; i++) {
+                       if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
+                          hose->mem_resources[i].start == hose->pci_mem_offset)
+                               return 0;
+               }
+
+               /* Well, it starts at 0 and we know it will collide so we may as
+                * well consider it as unassigned. That covers the Apple case.
+                */
+               return 1;
+       } else {
+               /* If the BAR is non-0, then we consider it assigned */
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               if (((res->start - offset) & 0xfffffffful) != 0)
+                       return 0;
+
+               /* Here, we are a bit different than memory as typically IO
+                * space starting at low addresses -is- valid. What we do
+                * instead if that we consider as unassigned anything that
+                * doesn't have IO enabled in the PCI command register,
+                * and that's it.
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if (command & PCI_COMMAND_IO)
+                       return 0;
+
+               /* It's starting at 0 and IO is disabled in the bridge, consider
+                * it unassigned
+                */
+               return 1;
+       }
+}
+
+/* Fixup resources of a PCI<->PCI bridge */
+static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+{
+       struct resource *res;
+       int i;
+
+       struct pci_dev *dev = bus->self;
+
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               res = bus->resource[i];
+               if (!res)
+                       continue;
+               if (!res->flags)
+                       continue;
+               if (i >= 3 && bus->self->transparent)
+                       continue;
+
+               pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+                        pci_name(dev), i,
+                        (unsigned long long)res->start,\
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags);
+
+               /* Perform fixup */
+               fixup_resource(res, dev);
+
+               /* Try to detect uninitialized P2P bridge resources,
+                * and clear them out so they get re-assigned later
+                */
+               if (pcibios_uninitialized_bridge_resource(bus, res)) {
+                       res->flags = 0;
+                       pr_debug("PCI:%s            (unassigned)\n",
+                                                               pci_name(dev));
+               } else {
+                       pr_debug("PCI:%s            %016llx-%016llx\n",
+                                pci_name(dev),
+                                (unsigned long long)res->start,
+                                (unsigned long long)res->end);
+               }
+       }
+}
+
+void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
+{
+       /* Fix up the bus resources for P2P bridges */
+       if (bus->self != NULL)
+               pcibios_fixup_bridge(bus);
+}
+
+void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       pr_debug("PCI: Fixup bus devices %d (%s)\n",
+                bus->number, bus->self ? pci_name(bus->self) : "PHB");
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               struct dev_archdata *sd = &dev->dev.archdata;
+
+               /* Setup OF node pointer in archdata */
+               sd->of_node = pci_device_to_OF_node(dev);
+
+               /* Fixup NUMA node as it may not be setup yet by the generic
+                * code and is needed by the DMA init
+                */
+               set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+               /* Hook up default DMA ops */
+               sd->dma_ops = pci_dma_ops;
+               sd->dma_data = (void *)PCI_DRAM_OFFSET;
+
+               /* Read default IRQs and fixup if necessary */
+               pci_read_irq_line(dev);
+       }
+}
+
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+       /* When called from the generic PCI probe, read PCI<->PCI bridge
+        * bases. This is -not- called when generating the PCI tree from
+        * the OF device-tree.
+        */
+       if (bus->self != NULL)
+               pci_read_bridge_bases(bus);
+
+       /* Now fixup the bus bus */
+       pcibios_setup_bus_self(bus);
+
+       /* Now fixup devices on that bus */
+       pcibios_setup_bus_devices(bus);
+}
+EXPORT_SYMBOL(pcibios_fixup_bus);
+
+static int skip_isa_ioresource_align(struct pci_dev *dev)
+{
+       if ((pci_flags & PCI_CAN_SKIP_ISA_ALIGN) &&
+           !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
+               return 1;
+       return 0;
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
+{
+       struct pci_dev *dev = data;
+
+       if (res->flags & IORESOURCE_IO) {
+               resource_size_t start = res->start;
+
+               if (skip_isa_ioresource_align(dev))
+                       return;
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+EXPORT_SYMBOL(pcibios_align_resource);
+
+/*
+ * Reparent resource children of pr that conflict with res
+ * under res, and make res replace those children.
+ */
+static int __init reparent_resources(struct resource *parent,
+                                    struct resource *res)
+{
+       struct resource *p, **pp;
+       struct resource **firstpp = NULL;
+
+       for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
+               if (p->end < res->start)
+                       continue;
+               if (res->end < p->start)
+                       break;
+               if (p->start < res->start || p->end > res->end)
+                       return -1;      /* not completely contained */
+               if (firstpp == NULL)
+                       firstpp = pp;
+       }
+       if (firstpp == NULL)
+               return -1;      /* didn't find any conflicting entries? */
+       res->parent = parent;
+       res->child = *firstpp;
+       res->sibling = *pp;
+       *firstpp = res;
+       *pp = NULL;
+       for (p = res->child; p != NULL; p = p->sibling) {
+               p->parent = res;
+               pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n",
+                        p->name,
+                        (unsigned long long)p->start,
+                        (unsigned long long)p->end, res->name);
+       }
+       return 0;
+}
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *     - I/O or memory regions not configured
+ *     - regions configured, but not enabled in the command register
+ *     - bogus I/O addresses above 64K used
+ *     - expansion ROMs left enabled (this may sound harmless, but given
+ *       the fact the PCI specs explicitly allow address decoders to be
+ *       shared between expansion ROMs and other resource regions, it's
+ *       at least dangerous)
+ *
+ *  Our solution:
+ *     (1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *         This gives us fixed barriers on where we can allocate.
+ *     (2) Allocate resources for all enabled devices.  If there is
+ *         a collision, just mark the resource as unallocated. Also
+ *         disable expansion ROMs during this step.
+ *     (3) Try to allocate resources for disabled devices.  If the
+ *         resources were assigned correctly, everything goes well,
+ *         if they weren't, they won't disturb allocation of other
+ *         resources.
+ *     (4) Assign new addresses to resources which were either
+ *         not configured at all or misconfigured.  If explicitly
+ *         requested by the user, configure expansion ROM address
+ *         as well.
+ */
+
+void pcibios_allocate_bus_resources(struct pci_bus *bus)
+{
+       struct pci_bus *b;
+       int i;
+       struct resource *res, *pr;
+
+       pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
+                pci_domain_nr(bus), bus->number);
+
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               res = bus->resource[i];
+               if (!res || !res->flags
+                   || res->start > res->end || res->parent)
+                       continue;
+               if (bus->parent == NULL)
+                       pr = (res->flags & IORESOURCE_IO) ?
+                               &ioport_resource : &iomem_resource;
+               else {
+                       /* Don't bother with non-root busses when
+                        * re-assigning all resources. We clear the
+                        * resource flags as if they were colliding
+                        * and as such ensure proper re-allocation
+                        * later.
+                        */
+                       if (pci_flags & PCI_REASSIGN_ALL_RSRC)
+                               goto clear_resource;
+                       pr = pci_find_parent_resource(bus->self, res);
+                       if (pr == res) {
+                               /* this happens when the generic PCI
+                                * code (wrongly) decides that this
+                                * bridge is transparent  -- paulus
+                                */
+                               continue;
+                       }
+               }
+
+               pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
+                        "[0x%x], parent %p (%s)\n",
+                        bus->self ? pci_name(bus->self) : "PHB",
+                        bus->number, i,
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags,
+                        pr, (pr && pr->name) ? pr->name : "nil");
+
+               if (pr && !(pr->flags & IORESOURCE_UNSET)) {
+                       if (request_resource(pr, res) == 0)
+                               continue;
+                       /*
+                        * Must be a conflict with an existing entry.
+                        * Move that entry (or entries) under the
+                        * bridge resource and try again.
+                        */
+                       if (reparent_resources(pr, res) == 0)
+                               continue;
+               }
+               printk(KERN_WARNING "PCI: Cannot allocate resource region "
+                      "%d of PCI bridge %d, will remap\n", i, bus->number);
+clear_resource:
+               res->flags = 0;
+       }
+
+       list_for_each_entry(b, &bus->children, node)
+               pcibios_allocate_bus_resources(b);
+}
+
+static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
+{
+       struct resource *pr, *r = &dev->resource[idx];
+
+       pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
+                pci_name(dev), idx,
+                (unsigned long long)r->start,
+                (unsigned long long)r->end,
+                (unsigned int)r->flags);
+
+       pr = pci_find_parent_resource(dev, r);
+       if (!pr || (pr->flags & IORESOURCE_UNSET) ||
+           request_resource(pr, r) < 0) {
+               printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
+                      " of device %s, will remap\n", idx, pci_name(dev));
+               if (pr)
+                       pr_debug("PCI:  parent is %p: %016llx-%016llx [%x]\n",
+                                pr,
+                                (unsigned long long)pr->start,
+                                (unsigned long long)pr->end,
+                                (unsigned int)pr->flags);
+               /* We'll assign a new address later */
+               r->flags |= IORESOURCE_UNSET;
+               r->end -= r->start;
+               r->start = 0;
+       }
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+       struct pci_dev *dev = NULL;
+       int idx, disabled;
+       u16 command;
+       struct resource *r;
+
+       for_each_pci_dev(dev) {
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
+                       r = &dev->resource[idx];
+                       if (r->parent)          /* Already allocated */
+                               continue;
+                       if (!r->flags || (r->flags & IORESOURCE_UNSET))
+                               continue;       /* Not assigned at all */
+                       /* We only allocate ROMs on pass 1 just in case they
+                        * have been screwed up by firmware
+                        */
+                       if (idx == PCI_ROM_RESOURCE)
+                               disabled = 1;
+                       if (r->flags & IORESOURCE_IO)
+                               disabled = !(command & PCI_COMMAND_IO);
+                       else
+                               disabled = !(command & PCI_COMMAND_MEMORY);
+                       if (pass == disabled)
+                               alloc_resource(dev, idx);
+               }
+               if (pass)
+                       continue;
+               r = &dev->resource[PCI_ROM_RESOURCE];
+               if (r->flags) {
+                       /* Turn the ROM off, leave the resource region,
+                        * but keep it unregistered.
+                        */
+                       u32 reg;
+                       pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+                       if (reg & PCI_ROM_ADDRESS_ENABLE) {
+                               pr_debug("PCI: Switching off ROM of %s\n",
+                                        pci_name(dev));
+                               r->flags &= ~IORESOURCE_ROM_ENABLE;
+                               pci_write_config_dword(dev, dev->rom_base_reg,
+                                               reg & ~PCI_ROM_ADDRESS_ENABLE);
+                       }
+               }
+       }
+}
+
+static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       resource_size_t offset;
+       struct resource *res, *pres;
+       int i;
+
+       pr_debug("Reserving legacy ranges for domain %04x\n",
+                                                       pci_domain_nr(bus));
+
+       /* Check for IO */
+       if (!(hose->io_resource.flags & IORESOURCE_IO))
+               goto no_io;
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy IO";
+       res->flags = IORESOURCE_IO;
+       res->start = offset;
+       res->end = (offset + 0xfff) & 0xfffffffful;
+       pr_debug("Candidate legacy IO: %pR\n", res);
+       if (request_resource(&hose->io_resource, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve Legacy IO %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+
+ no_io:
+       /* Check for memory */
+       offset = hose->pci_mem_offset;
+       pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
+       for (i = 0; i < 3; i++) {
+               pres = &hose->mem_resources[i];
+               if (!(pres->flags & IORESOURCE_MEM))
+                       continue;
+               pr_debug("hose mem res: %pR\n", pres);
+               if ((pres->start - offset) <= 0xa0000 &&
+                   (pres->end - offset) >= 0xbffff)
+                       break;
+       }
+       if (i >= 3)
+               return;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy VGA memory";
+       res->flags = IORESOURCE_MEM;
+       res->start = 0xa0000 + offset;
+       res->end = 0xbffff + offset;
+       pr_debug("Candidate VGA memory: %pR\n", res);
+       if (request_resource(pres, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve VGA memory %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+}
+
+void __init pcibios_resource_survey(void)
+{
+       struct pci_bus *b;
+
+       /* Allocate and assign resources. If we re-assign everything, then
+        * we skip the allocate phase
+        */
+       list_for_each_entry(b, &pci_root_buses, node)
+               pcibios_allocate_bus_resources(b);
+
+       if (!(pci_flags & PCI_REASSIGN_ALL_RSRC)) {
+               pcibios_allocate_resources(0);
+               pcibios_allocate_resources(1);
+       }
+
+       /* Before we start assigning unassigned resource, we try to reserve
+        * the low IO area and the VGA memory area if they intersect the
+        * bus available resources to avoid allocating things on top of them
+        */
+       if (!(pci_flags & PCI_PROBE_ONLY)) {
+               list_for_each_entry(b, &pci_root_buses, node)
+                       pcibios_reserve_legacy_regions(b);
+       }
+
+       /* Now, if the platform didn't decide to blindly trust the firmware,
+        * we proceed to assigning things that were left unassigned
+        */
+       if (!(pci_flags & PCI_PROBE_ONLY)) {
+               pr_debug("PCI: Assigning unassigned resources...\n");
+               pci_assign_unassigned_resources();
+       }
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/* This is used by the PCI hotplug driver to allocate resource
+ * of newly plugged busses. We can try to consolidate with the
+ * rest of the code later, for now, keep it as-is as our main
+ * resource allocation function doesn't deal with sub-trees yet.
+ */
+void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+       struct pci_bus *child_bus;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               int i;
+
+               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                       struct resource *r = &dev->resource[i];
+
+                       if (r->parent || !r->start || !r->flags)
+                               continue;
+
+                       pr_debug("PCI: Claiming %s: "
+                                "Resource %d: %016llx..%016llx [%x]\n",
+                                pci_name(dev), i,
+                                (unsigned long long)r->start,
+                                (unsigned long long)r->end,
+                                (unsigned int)r->flags);
+
+                       pci_claim_resource(dev, i);
+               }
+       }
+
+       list_for_each_entry(child_bus, &bus->children, node)
+               pcibios_claim_one_bus(child_bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
+
+
+/* pcibios_finish_adding_to_bus
+ *
+ * This is to be called by the hotplug code after devices have been
+ * added to a bus, this include calling it for a PHB that is just
+ * being added
+ */
+void pcibios_finish_adding_to_bus(struct pci_bus *bus)
+{
+       pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n",
+                pci_domain_nr(bus), bus->number);
+
+       /* Allocate bus and devices resources */
+       pcibios_allocate_bus_resources(bus);
+       pcibios_claim_one_bus(bus);
+
+       /* Add new devices to global lists.  Register in proc, sysfs. */
+       pci_bus_add_devices(bus);
+
+       /* Fixup EEH */
+       eeh_add_device_tree_late(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
+
+#endif /* CONFIG_HOTPLUG */
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       return pci_enable_resources(dev, mask);
+}
+
+void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
+{
+       struct pci_bus *bus = hose->bus;
+       struct resource *res;
+       int i;
+
+       /* Hookup PHB IO resource */
+       bus->resource[0] = res = &hose->io_resource;
+
+       if (!res->flags) {
+               printk(KERN_WARNING "PCI: I/O resource not set for host"
+                      " bridge %s (domain %d)\n",
+                      hose->dn->full_name, hose->global_number);
+               /* Workaround for lack of IO resource only on 32-bit */
+               res->start = (unsigned long)hose->io_base_virt - isa_io_base;
+               res->end = res->start + IO_SPACE_LIMIT;
+               res->flags = IORESOURCE_IO;
+       }
+
+       pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
+                (unsigned long long)res->start,
+                (unsigned long long)res->end,
+                (unsigned long)res->flags);
+
+       /* Hookup PHB Memory resources */
+       for (i = 0; i < 3; ++i) {
+               res = &hose->mem_resources[i];
+               if (!res->flags) {
+                       if (i > 0)
+                               continue;
+                       printk(KERN_ERR "PCI: Memory resource 0 not set for "
+                              "host bridge %s (domain %d)\n",
+                              hose->dn->full_name, hose->global_number);
+
+                       /* Workaround for lack of MEM resource only on 32-bit */
+                       res->start = hose->pci_mem_offset;
+                       res->end = (resource_size_t)-1LL;
+                       res->flags = IORESOURCE_MEM;
+
+               }
+               bus->resource[i+1] = res;
+
+               pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
+                       i, (unsigned long long)res->start,
+                       (unsigned long long)res->end,
+                       (unsigned long)res->flags);
+       }
+
+       pr_debug("PCI: PHB MEM offset     = %016llx\n",
+                (unsigned long long)hose->pci_mem_offset);
+       pr_debug("PCI: PHB IO  offset     = %08lx\n",
+                (unsigned long)hose->io_base_virt - _IO_BASE);
+}
+
+/*
+ * Null PCI config access functions, for the case when we can't
+ * find a hose.
+ */
+#define NULL_PCI_OP(rw, size, type)                                    \
+static int                                                             \
+null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)   \
+{                                                                      \
+       return PCIBIOS_DEVICE_NOT_FOUND;                                \
+}
+
+static int
+null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                int len, u32 *val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int
+null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                 int len, u32 val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static struct pci_ops null_pci_ops = {
+       .read = null_read_config,
+       .write = null_write_config,
+};
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_bus *
+fake_pci_bus(struct pci_controller *hose, int busnr)
+{
+       static struct pci_bus bus;
+
+       if (!hose)
+               printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
+
+       bus.number = busnr;
+       bus.sysdata = hose;
+       bus.ops = hose ? hose->ops : &null_pci_ops;
+       return &bus;
+}
+
+#define EARLY_PCI_OP(rw, size, type)                                   \
+int early_##rw##_config_##size(struct pci_controller *hose, int bus,   \
+                              int devfn, int offset, type value)       \
+{                                                                      \
+       return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus),    \
+                                           devfn, offset, value);      \
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
+int early_find_capability(struct pci_controller *hose, int bus, int devfn,
+                         int cap)
+{
+       return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
+}
diff --git a/arch/microblaze/pci/pci_32.c b/arch/microblaze/pci/pci_32.c
new file mode 100644 (file)
index 0000000..7e0c94f
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Common pmac/prep/chrp pci routines. -- Cort
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#undef DEBUG
+
+unsigned long isa_io_base;
+unsigned long pci_dram_offset;
+int pcibios_assign_bus_offset = 1;
+
+static u8 *pci_to_OF_bus_map;
+
+/* By default, we don't re-assign bus numbers. We do this only on
+ * some pmacs
+ */
+static int pci_assign_all_buses;
+
+static int pci_bus_count;
+
+/*
+ * Functions below are used on OpenFirmware machines.
+ */
+static void
+make_one_node_map(struct device_node *node, u8 pci_bus)
+{
+       const int *bus_range;
+       int len;
+
+       if (pci_bus >= pci_bus_count)
+               return;
+       bus_range = of_get_property(node, "bus-range", &len);
+       if (bus_range == NULL || len < 2 * sizeof(int)) {
+               printk(KERN_WARNING "Can't get bus-range for %s, "
+                      "assuming it starts at 0\n", node->full_name);
+               pci_to_OF_bus_map[pci_bus] = 0;
+       } else
+               pci_to_OF_bus_map[pci_bus] = bus_range[0];
+
+       for_each_child_of_node(node, node) {
+               struct pci_dev *dev;
+               const unsigned int *class_code, *reg;
+
+               class_code = of_get_property(node, "class-code", NULL);
+               if (!class_code ||
+                       ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+                       continue;
+               reg = of_get_property(node, "reg", NULL);
+               if (!reg)
+                       continue;
+               dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+               if (!dev || !dev->subordinate) {
+                       pci_dev_put(dev);
+                       continue;
+               }
+               make_one_node_map(node, dev->subordinate->number);
+               pci_dev_put(dev);
+       }
+}
+
+void
+pcibios_make_OF_bus_map(void)
+{
+       int i;
+       struct pci_controller *hose, *tmp;
+       struct property *map_prop;
+       struct device_node *dn;
+
+       pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
+       if (!pci_to_OF_bus_map) {
+               printk(KERN_ERR "Can't allocate OF bus map !\n");
+               return;
+       }
+
+       /* We fill the bus map with invalid values, that helps
+        * debugging.
+        */
+       for (i = 0; i < pci_bus_count; i++)
+               pci_to_OF_bus_map[i] = 0xff;
+
+       /* For each hose, we begin searching bridges */
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               struct device_node *node = hose->dn;
+
+               if (!node)
+                       continue;
+               make_one_node_map(node, hose->first_busno);
+       }
+       dn = of_find_node_by_path("/");
+       map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);
+       if (map_prop) {
+               BUG_ON(pci_bus_count > map_prop->length);
+               memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
+       }
+       of_node_put(dn);
+#ifdef DEBUG
+       printk(KERN_INFO "PCI->OF bus map:\n");
+       for (i = 0; i < pci_bus_count; i++) {
+               if (pci_to_OF_bus_map[i] == 0xff)
+                       continue;
+               printk(KERN_INFO "%d -> %d\n", i, pci_to_OF_bus_map[i]);
+       }
+#endif
+}
+
+typedef int (*pci_OF_scan_iterator)(struct device_node *node, void *data);
+
+static struct device_node *scan_OF_pci_childs(struct device_node *parent,
+                                       pci_OF_scan_iterator filter, void *data)
+{
+       struct device_node *node;
+       struct device_node *sub_node;
+
+       for_each_child_of_node(parent, node) {
+               const unsigned int *class_code;
+
+               if (filter(node, data)) {
+                       of_node_put(node);
+                       return node;
+               }
+
+               /* For PCI<->PCI bridges or CardBus bridges, we go down
+                * Note: some OFs create a parent node "multifunc-device" as
+                * a fake root for all functions of a multi-function device,
+                * we go down them as well.
+                */
+               class_code = of_get_property(node, "class-code", NULL);
+               if ((!class_code ||
+                       ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
+                       strcmp(node->name, "multifunc-device"))
+                       continue;
+               sub_node = scan_OF_pci_childs(node, filter, data);
+               if (sub_node) {
+                       of_node_put(node);
+                       return sub_node;
+               }
+       }
+       return NULL;
+}
+
+static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
+                                              unsigned int devfn)
+{
+       struct device_node *np, *cnp;
+       const u32 *reg;
+       unsigned int psize;
+
+       for_each_child_of_node(parent, np) {
+               reg = of_get_property(np, "reg", &psize);
+               if (reg && psize >= 4 && ((reg[0] >> 8) & 0xff) == devfn)
+                       return np;
+
+               /* Note: some OFs create a parent node "multifunc-device" as
+                * a fake root for all functions of a multi-function device,
+                * we go down them as well. */
+               if (!strcmp(np->name, "multifunc-device")) {
+                       cnp = scan_OF_for_pci_dev(np, devfn);
+                       if (cnp)
+                               return cnp;
+               }
+       }
+       return NULL;
+}
+
+
+static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
+{
+       struct device_node *parent, *np;
+
+       /* Are we a root bus ? */
+       if (bus->self == NULL || bus->parent == NULL) {
+               struct pci_controller *hose = pci_bus_to_host(bus);
+               if (hose == NULL)
+                       return NULL;
+               return of_node_get(hose->dn);
+       }
+
+       /* not a root bus, we need to get our parent */
+       parent = scan_OF_for_pci_bus(bus->parent);
+       if (parent == NULL)
+               return NULL;
+
+       /* now iterate for children for a match */
+       np = scan_OF_for_pci_dev(parent, bus->self->devfn);
+       of_node_put(parent);
+
+       return np;
+}
+
+/*
+ * Scans the OF tree for a device node matching a PCI device
+ */
+struct device_node *
+pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
+{
+       struct device_node *parent, *np;
+
+       pr_debug("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
+       parent = scan_OF_for_pci_bus(bus);
+       if (parent == NULL)
+               return NULL;
+       pr_debug(" parent is %s\n", parent ? parent->full_name : "<NULL>");
+       np = scan_OF_for_pci_dev(parent, devfn);
+       of_node_put(parent);
+       pr_debug(" result is %s\n", np ? np->full_name : "<NULL>");
+
+       /* XXX most callers don't release the returned node
+        * mostly because ppc64 doesn't increase the refcount,
+        * we need to fix that.
+        */
+       return np;
+}
+EXPORT_SYMBOL(pci_busdev_to_OF_node);
+
+struct device_node*
+pci_device_to_OF_node(struct pci_dev *dev)
+{
+       return pci_busdev_to_OF_node(dev->bus, dev->devfn);
+}
+EXPORT_SYMBOL(pci_device_to_OF_node);
+
+static int
+find_OF_pci_device_filter(struct device_node *node, void *data)
+{
+       return ((void *)node == data);
+}
+
+/*
+ * Returns the PCI device matching a given OF node
+ */
+int
+pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
+{
+       const unsigned int *reg;
+       struct pci_controller *hose;
+       struct pci_dev *dev = NULL;
+
+       /* Make sure it's really a PCI device */
+       hose = pci_find_hose_for_OF_device(node);
+       if (!hose || !hose->dn)
+               return -ENODEV;
+       if (!scan_OF_pci_childs(hose->dn,
+                       find_OF_pci_device_filter, (void *)node))
+               return -ENODEV;
+       reg = of_get_property(node, "reg", NULL);
+       if (!reg)
+               return -ENODEV;
+       *bus = (reg[0] >> 16) & 0xff;
+       *devfn = ((reg[0] >> 8) & 0xff);
+
+       /* Ok, here we need some tweak. If we have already renumbered
+        * all busses, we can't rely on the OF bus number any more.
+        * the pci_to_OF_bus_map is not enough as several PCI busses
+        * may match the same OF bus number.
+        */
+       if (!pci_to_OF_bus_map)
+               return 0;
+
+       for_each_pci_dev(dev)
+               if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
+                               dev->devfn == *devfn) {
+                       *bus = dev->bus->number;
+                       pci_dev_put(dev);
+                       return 0;
+               }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(pci_device_from_OF_node);
+
+/* We create the "pci-OF-bus-map" property now so it appears in the
+ * /proc device tree
+ */
+void __init
+pci_create_OF_bus_map(void)
+{
+       struct property *of_prop;
+       struct device_node *dn;
+
+       of_prop = (struct property *) alloc_bootmem(sizeof(struct property) + \
+                                                                        256);
+       if (!of_prop)
+               return;
+       dn = of_find_node_by_path("/");
+       if (dn) {
+               memset(of_prop, -1, sizeof(struct property) + 256);
+               of_prop->name = "pci-OF-bus-map";
+               of_prop->length = 256;
+               of_prop->value = &of_prop[1];
+               prom_add_property(dn, of_prop);
+               of_node_put(dn);
+       }
+}
+
+static void __devinit pcibios_scan_phb(struct pci_controller *hose)
+{
+       struct pci_bus *bus;
+       struct device_node *node = hose->dn;
+       unsigned long io_offset;
+       struct resource *res = &hose->io_resource;
+
+       pr_debug("PCI: Scanning PHB %s\n",
+                node ? node->full_name : "<NO NAME>");
+
+       /* Create an empty bus for the toplevel */
+       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
+       if (bus == NULL) {
+               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
+                      hose->global_number);
+               return;
+       }
+       bus->secondary = hose->first_busno;
+       hose->bus = bus;
+
+       /* Fixup IO space offset */
+       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       res->start = (res->start + io_offset) & 0xffffffffu;
+       res->end = (res->end + io_offset) & 0xffffffffu;
+
+       /* Wire up PHB bus resources */
+       pcibios_setup_phb_resources(hose);
+
+       /* Scan children */
+       hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+}
+
+static int __init pcibios_init(void)
+{
+       struct pci_controller *hose, *tmp;
+       int next_busno = 0;
+
+       printk(KERN_INFO "PCI: Probing PCI hardware\n");
+
+       if (pci_flags & PCI_REASSIGN_ALL_BUS) {
+               printk(KERN_INFO "setting pci_asign_all_busses\n");
+               pci_assign_all_buses = 1;
+       }
+
+       /* Scan all of the recorded PCI controllers.  */
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               if (pci_assign_all_buses)
+                       hose->first_busno = next_busno;
+               hose->last_busno = 0xff;
+               pcibios_scan_phb(hose);
+               printk(KERN_INFO "calling pci_bus_add_devices()\n");
+               pci_bus_add_devices(hose->bus);
+               if (pci_assign_all_buses || next_busno <= hose->last_busno)
+                       next_busno = hose->last_busno + \
+                                       pcibios_assign_bus_offset;
+       }
+       pci_bus_count = next_busno;
+
+       /* OpenFirmware based machines need a map of OF bus
+        * numbers vs. kernel bus numbers since we may have to
+        * remap them.
+        */
+       if (pci_assign_all_buses)
+               pcibios_make_OF_bus_map();
+
+       /* Call common code to handle resource allocation */
+       pcibios_resource_survey();
+
+       return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+static struct pci_controller*
+pci_bus_to_hose(int bus)
+{
+       struct pci_controller *hose, *tmp;
+
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+               if (bus >= hose->first_busno && bus <= hose->last_busno)
+                       return hose;
+       return NULL;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+       struct pci_controller *hose;
+       long result = -EOPNOTSUPP;
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return -ENODEV;
+
+       switch (which) {
+       case IOBASE_BRIDGE_NUMBER:
+               return (long)hose->first_busno;
+       case IOBASE_MEMORY:
+               return (long)hose->pci_mem_offset;
+       case IOBASE_IO:
+               return (long)hose->io_base_phys;
+       case IOBASE_ISA_IO:
+               return (long)isa_io_base;
+       case IOBASE_ISA_MEM:
+               return (long)isa_mem_base;
+       }
+
+       return result;
+}
diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c
new file mode 100644 (file)
index 0000000..7869a41
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * PCI support for Xilinx plbv46_pci soft-core which can be used on
+ * Xilinx Virtex ML410 / ML510 boards.
+ *
+ * Copyright 2009 Roderick Colenbrander
+ * Copyright 2009 Secret Lab Technologies Ltd.
+ *
+ * The pci bridge fixup code was copied from ppc4xx_pci.c and was written
+ * by Benjamin Herrenschmidt.
+ * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#define XPLB_PCI_ADDR 0x10c
+#define XPLB_PCI_DATA 0x110
+#define XPLB_PCI_BUS  0x114
+
+#define PCI_HOST_ENABLE_CMD (PCI_COMMAND_SERR | PCI_COMMAND_PARITY | \
+                               PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)
+
+static struct of_device_id xilinx_pci_match[] = {
+       { .compatible = "xlnx,plbv46-pci-1.03.a", },
+       {}
+};
+
+/**
+ * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration.
+ */
+static void xilinx_pci_fixup_bridge(struct pci_dev *dev)
+{
+       struct pci_controller *hose;
+       int i;
+
+       if (dev->devfn || dev->bus->self)
+               return;
+
+       hose = pci_bus_to_host(dev->bus);
+       if (!hose)
+               return;
+
+       if (!of_match_node(xilinx_pci_match, hose->dn))
+               return;
+
+       /* Hide the PCI host BARs from the kernel as their content doesn't
+        * fit well in the resource management
+        */
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               dev->resource[i].start = 0;
+               dev->resource[i].end = 0;
+               dev->resource[i].flags = 0;
+       }
+
+       dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n",
+                pci_name(dev));
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge);
+
+#ifdef DEBUG
+/**
+ * xilinx_pci_exclude_device - Don't do config access for non-root bus
+ *
+ * This is a hack.  Config access to any bus other than bus 0 does not
+ * currently work on the ML510 so we prevent it here.
+ */
+static int
+xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn)
+{
+       return (bus != 0);
+}
+
+/**
+ * xilinx_early_pci_scan - List pci config space for available devices
+ *
+ * List pci devices in very early phase.
+ */
+void __init xilinx_early_pci_scan(struct pci_controller *hose)
+{
+       u32 bus = 0;
+       u32 val, dev, func, offset;
+
+       /* Currently we have only 2 device connected - up-to 32 devices */
+       for (dev = 0; dev < 2; dev++) {
+               /* List only first function number - up-to 8 functions */
+               for (func = 0; func < 1; func++) {
+                       printk(KERN_INFO "%02x:%02x:%02x", bus, dev, func);
+                       /* read the first 64 standardized bytes */
+                       /* Up-to 192 bytes can be list of capabilities */
+                       for (offset = 0; offset < 64; offset += 4) {
+                               early_read_config_dword(hose, bus,
+                                       PCI_DEVFN(dev, func), offset, &val);
+                               if (offset == 0 && val == 0xFFFFFFFF) {
+                                       printk(KERN_CONT "\nABSENT");
+                                       break;
+                               }
+                               if (!(offset % 0x10))
+                                       printk(KERN_CONT "\n%04x:    ", offset);
+
+                               printk(KERN_CONT "%08x  ", val);
+                       }
+                       printk(KERN_INFO "\n");
+               }
+       }
+}
+#else
+void __init xilinx_early_pci_scan(struct pci_controller *hose)
+{
+}
+#endif
+
+/**
+ * xilinx_pci_init - Find and register a Xilinx PCI host bridge
+ */
+void __init xilinx_pci_init(void)
+{
+       struct pci_controller *hose;
+       struct resource r;
+       void __iomem *pci_reg;
+       struct device_node *pci_node;
+
+       pci_node = of_find_matching_node(NULL, xilinx_pci_match);
+       if (!pci_node)
+               return;
+
+       if (of_address_to_resource(pci_node, 0, &r)) {
+               pr_err("xilinx-pci: cannot resolve base address\n");
+               return;
+       }
+
+       hose = pcibios_alloc_controller(pci_node);
+       if (!hose) {
+               pr_err("xilinx-pci: pcibios_alloc_controller() failed\n");
+               return;
+       }
+
+       /* Setup config space */
+       setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR,
+                          r.start + XPLB_PCI_DATA,
+                          INDIRECT_TYPE_SET_CFG_TYPE);
+
+       /* According to the xilinx plbv46_pci documentation the soft-core starts
+        * a self-init when the bus master enable bit is set. Without this bit
+        * set the pci bus can't be scanned.
+        */
+       early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD);
+
+       /* Set the max latency timer to 255 */
+       early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff);
+
+       /* Set the max bus number to 255, and bus/subbus no's to 0 */
+       pci_reg = of_iomap(pci_node, 0);
+       out_be32(pci_reg + XPLB_PCI_BUS, 0x000000ff);
+       iounmap(pci_reg);
+
+       /* Register the host bridge with the linux kernel! */
+       pci_process_bridge_OF_ranges(hose, pci_node,
+                                       INDIRECT_TYPE_SET_CFG_TYPE);
+
+       pr_info("xilinx-pci: Registered PCI host bridge\n");
+       xilinx_early_pci_scan(hose);
+}
index ff9bdb2..218d49b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 14:45:07 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:34:22 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -94,11 +94,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -109,6 +104,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -340,7 +336,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=y
@@ -517,6 +512,8 @@ CONFIG_MTD_PHYSMAP_OF=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -684,6 +681,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=57600
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -714,6 +712,7 @@ CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -754,6 +753,7 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
 # CONFIG_MPC5200_WDT is not set
 
 #
@@ -771,18 +771,20 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
-# CONFIG_MFD_88PM8607 is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -813,7 +815,6 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
@@ -891,7 +892,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -903,7 +903,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
@@ -1009,6 +1008,7 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
index 7b3f4d0..90492ff 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 14:45:09 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:34:24 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -95,11 +95,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -110,6 +105,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -317,6 +313,7 @@ CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_HIBERNATION is not set
 # CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
 CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
 
@@ -333,7 +330,6 @@ CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY=y
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
 # CONFIG_PCI_IOV is not set
@@ -360,7 +356,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
@@ -457,6 +452,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -631,6 +628,7 @@ CONFIG_ATA_SFF=y
 # CONFIG_PATA_IT821X is not set
 # CONFIG_PATA_IT8213 is not set
 # CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
 CONFIG_PATA_MPC52xx=y
@@ -668,7 +666,7 @@ CONFIG_PATA_MPC52xx=y
 #
 
 #
-# See the help texts for more information.
+# The newer stack is recommended.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
@@ -768,6 +766,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
 # CONFIG_MLX4_CORE is not set
 # CONFIG_TEHUTI is not set
 # CONFIG_BNX2X is not set
+# CONFIG_QLCNIC is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
 # CONFIG_BE2NET is not set
@@ -828,6 +827,7 @@ CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
 # CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -879,6 +879,7 @@ CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -924,18 +925,21 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
-# CONFIG_MFD_88PM8607 is not set
+# CONFIG_LPC_SCH is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -944,6 +948,7 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_AGP is not set
 CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
 # CONFIG_DRM is not set
 # CONFIG_VGASTATE is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=m
@@ -1062,6 +1067,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
index eaae2d4..dffc8ca 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 14:45:08 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:34:23 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -94,11 +94,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -109,6 +104,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -341,7 +337,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=y
@@ -518,6 +513,8 @@ CONFIG_MTD_ROM=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -699,6 +696,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -728,6 +726,7 @@ CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -773,10 +772,11 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
@@ -811,6 +811,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
 # CONFIG_SENSORS_TMP421 is not set
@@ -831,6 +832,7 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
 # CONFIG_MPC5200_WDT is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -843,18 +845,20 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
-# CONFIG_MFD_88PM8607 is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -1050,6 +1054,7 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
index 1742c02..3cb2a52 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 14:45:10 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:34:25 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -97,11 +97,6 @@ CONFIG_RCU_FANOUT=32
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -326,7 +321,6 @@ CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY=y
 # CONFIG_PCI_STUB is not set
 # CONFIG_PCI_IOV is not set
 # CONFIG_PCCARD is not set
@@ -352,7 +346,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -525,6 +518,8 @@ CONFIG_MTD_PHYSMAP=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -610,6 +605,7 @@ CONFIG_ATA_SFF=y
 # CONFIG_PATA_IT821X is not set
 # CONFIG_PATA_IT8213 is not set
 # CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
 CONFIG_PATA_MPC52xx=m
@@ -647,7 +643,7 @@ CONFIG_PATA_MPC52xx=m
 #
 
 #
-# See the help texts for more information.
+# The newer stack is recommended.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
@@ -775,6 +771,7 @@ CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=9600
 # CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -824,6 +821,7 @@ CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -870,18 +868,21 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
-# CONFIG_MFD_88PM8607 is not set
+# CONFIG_LPC_SCH is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -890,6 +891,7 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_AGP is not set
 CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
 # CONFIG_DRM is not set
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
@@ -997,7 +999,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1009,7 +1010,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
@@ -1172,6 +1172,7 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
index 3972438..96181c6 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 14:45:09 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:34:24 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -94,11 +94,6 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -109,6 +104,7 @@ CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -346,7 +342,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=y
@@ -524,6 +519,8 @@ CONFIG_MTD_PHYSMAP_OF=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -704,6 +701,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -733,6 +731,7 @@ CONFIG_I2C_HELPER_AUTO=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -780,10 +779,11 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
@@ -818,6 +818,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
 # CONFIG_SENSORS_TMP421 is not set
@@ -838,6 +839,7 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
 # CONFIG_MPC5200_WDT is not set
 
 #
@@ -855,18 +857,20 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_AB3100_CORE is not set
-# CONFIG_MFD_88PM8607 is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -897,7 +901,6 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
@@ -975,7 +978,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -987,7 +989,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
@@ -1151,6 +1152,7 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
index 61cf73d..7012ac0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc2
-# Wed Dec 30 15:08:52 2009
+# Linux kernel version: 2.6.34-rc1
+# Wed Mar 10 14:38:54 2010
 #
 # CONFIG_PPC64 is not set
 
@@ -96,30 +96,37 @@ CONFIG_RCU_FANOUT=32
 # CONFIG_TREE_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
-# CONFIG_NAMESPACES is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_KALLSYMS is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
+CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
@@ -141,6 +148,7 @@ CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
 CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
 CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
@@ -320,6 +328,7 @@ CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_HIBERNATION is not set
 # CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
 CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
 
@@ -336,7 +345,6 @@ CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY=y
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
 # CONFIG_PCI_IOV is not set
@@ -363,7 +371,6 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
@@ -454,7 +461,9 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_DEVTMPFS is not set
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
@@ -554,6 +563,8 @@ CONFIG_MTD_UBI_BEB_RESERVE=1
 # UBI debugging options
 #
 # CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
 CONFIG_OF_DEVICE=y
 CONFIG_OF_GPIO=y
 CONFIG_OF_I2C=y
@@ -732,6 +743,7 @@ CONFIG_ATA_SFF=y
 # CONFIG_PATA_IT821X is not set
 # CONFIG_PATA_IT8213 is not set
 # CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
 CONFIG_PATA_MPC52xx=y
@@ -770,7 +782,7 @@ CONFIG_PATA_PLATFORM=y
 #
 
 #
-# See the help texts for more information.
+# The newer stack is recommended.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
@@ -929,6 +941,7 @@ CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
 # CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
 # CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
@@ -981,6 +994,7 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
 
 #
 # External I2C/SMBus adapter drivers
@@ -1010,9 +1024,9 @@ CONFIG_SPI_MASTER=y
 #
 # SPI Master Controller Drivers
 #
-# CONFIG_SPI_BITBANG is not set
-# CONFIG_SPI_GPIO is not set
-# CONFIG_SPI_MPC52xx is not set
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_MPC52xx=m
 CONFIG_SPI_MPC52xx_PSC=m
 # CONFIG_SPI_XILINX is not set
 # CONFIG_SPI_DESIGNWARE is not set
@@ -1036,14 +1050,18 @@ CONFIG_GPIOLIB=y
 #
 # Memory mapped GPIO expanders:
 #
+# CONFIG_GPIO_IT8761E is not set
 # CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_SCH is not set
 
 #
 # I2C GPIO expanders:
 #
+# CONFIG_GPIO_MAX7300 is not set
 # CONFIG_GPIO_MAX732X is not set
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
 
 #
 # PCI GPIO expanders:
@@ -1080,10 +1098,11 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
 # CONFIG_SENSORS_ADT7462 is not set
 # CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
 # CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_I5K_AMB is not set
@@ -1123,6 +1142,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_AMC6821 is not set
 # CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_TMP401 is not set
 # CONFIG_SENSORS_TMP421 is not set
@@ -1147,6 +1167,7 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
 # CONFIG_ALIM7101_WDT is not set
 # CONFIG_MPC5200_WDT is not set
 # CONFIG_WATCHDOG_RTAS is not set
@@ -1172,22 +1193,27 @@ CONFIG_SSB_POSSIBLE=y
 # Multifunction device drivers
 #
 # CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
 # CONFIG_TPS65010 is not set
 # CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
 # CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM831X is not set
 # CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
 # CONFIG_MFD_PCF50633 is not set
 # CONFIG_MFD_MC13783 is not set
 # CONFIG_AB3100_CORE is not set
 # CONFIG_EZX_PCAP is not set
-# CONFIG_MFD_88PM8607 is not set
 # CONFIG_AB4500_CORE is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_LPC_SCH is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
@@ -1196,6 +1222,7 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_AGP is not set
 CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
 CONFIG_DRM=y
 # CONFIG_DRM_TDFX is not set
 # CONFIG_DRM_R128 is not set
@@ -1309,32 +1336,46 @@ CONFIG_USB_HID=y
 #
 # Special HID drivers
 #
+# CONFIG_HID_3M_PCT is not set
 CONFIG_HID_A4TECH=y
-# CONFIG_HID_APPLE is not set
+CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
-# CONFIG_HID_CHICONY is not set
+CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
-# CONFIG_HID_DRAGONRISE is not set
+CONFIG_HID_DRAGONRISE=y
+# CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
-# CONFIG_HID_KYE is not set
-# CONFIG_HID_GYRATION is not set
-# CONFIG_HID_TWINHAN is not set
-# CONFIG_HID_KENSINGTON is not set
-# CONFIG_HID_LOGITECH is not set
-# CONFIG_HID_MICROSOFT is not set
-# CONFIG_HID_MONTEREY is not set
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
 # CONFIG_HID_NTRIG is not set
-# CONFIG_HID_PANTHERLORD is not set
-# CONFIG_HID_PETALYNX is not set
-# CONFIG_HID_SAMSUNG is not set
-# CONFIG_HID_SONY is not set
-# CONFIG_HID_SUNPLUS is not set
-# CONFIG_HID_GREENASIA is not set
-# CONFIG_HID_SMARTJOYPLUS is not set
-# CONFIG_HID_TOPSEED is not set
-# CONFIG_HID_THRUSTMASTER is not set
-# CONFIG_HID_ZEROPLUS is not set
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+# CONFIG_HID_QUANTA is not set
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+# CONFIG_HID_STANTUM is not set
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1349,10 +1390,7 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
 CONFIG_USB_MON=y
 # CONFIG_USB_WUSB is not set
 # CONFIG_USB_WUSB_CBAF is not set
@@ -1433,7 +1471,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1445,7 +1482,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
@@ -1636,6 +1672,7 @@ CONFIG_UBIFS_FS=m
 CONFIG_UBIFS_FS_LZO=y
 CONFIG_UBIFS_FS_ZLIB=y
 # CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -1730,8 +1767,11 @@ CONFIG_CRC32=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
 CONFIG_LZO_COMPRESS=m
-CONFIG_LZO_DECOMPRESS=m
+CONFIG_LZO_DECOMPRESS=y
 CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
@@ -1776,11 +1816,11 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
-# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
index 5120bd4..08460a2 100644 (file)
@@ -1287,7 +1287,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
                irq_exit();
 }
 
-void hw_perf_event_setup(int cpu)
+static void power_pmu_setup(int cpu)
 {
        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
 
@@ -1297,6 +1297,23 @@ void hw_perf_event_setup(int cpu)
        cpuhw->mmcr[0] = MMCR0_FC;
 }
 
+static int __cpuinit
+power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               power_pmu_setup(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 int register_power_pmu(struct power_pmu *pmu)
 {
        if (ppmu)
@@ -1314,5 +1331,7 @@ int register_power_pmu(struct power_pmu *pmu)
                freeze_events_kernel = MMCR0_FCHV;
 #endif /* CONFIG_PPC64 */
 
+       perf_cpu_notifier(power_pmu_notifier);
+
        return 0;
 }
index 072b948..5d7cc88 100644 (file)
@@ -711,7 +711,11 @@ static int __devinit mpc52xx_gpt_wdt_init(void)
        return 0;
 }
 
-#define mpc52xx_gpt_wdt_setup(x, y)            (0)
+static inline int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt,
+                                       const u32 *period)
+{
+       return 0;
+}
 
 #endif /*  CONFIG_MPC5200_WDT  */
 
index 7ff0943..9f253e9 100644 (file)
@@ -275,13 +275,30 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        return &pmu;
 }
 
-void hw_perf_event_setup(int cpu)
+static void sh_pmu_setup(int cpu)
 {
        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
 
        memset(cpuhw, 0, sizeof(struct cpu_hw_events));
 }
 
+static int __cpuinit
+sh_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               sh_pmu_setup(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 void hw_perf_enable(void)
 {
        if (!sh_pmu_initialized())
@@ -308,5 +325,6 @@ int register_sh_pmu(struct sh_pmu *pmu)
 
        WARN_ON(pmu->num_events > MAX_HWEVENTS);
 
+       perf_cpu_notifier(sh_pmu_notifier);
        return 0;
 }
index 42aafd1..60398a0 100644 (file)
@@ -133,8 +133,8 @@ struct x86_pmu {
        int             (*handle_irq)(struct pt_regs *);
        void            (*disable_all)(void);
        void            (*enable_all)(void);
-       void            (*enable)(struct hw_perf_event *, int);
-       void            (*disable)(struct hw_perf_event *, int);
+       void            (*enable)(struct perf_event *);
+       void            (*disable)(struct perf_event *);
        unsigned        eventsel;
        unsigned        perfctr;
        u64             (*event_map)(int);
@@ -157,6 +157,11 @@ struct x86_pmu {
        void            (*put_event_constraints)(struct cpu_hw_events *cpuc,
                                                 struct perf_event *event);
        struct event_constraint *event_constraints;
+
+       void            (*cpu_prepare)(int cpu);
+       void            (*cpu_starting)(int cpu);
+       void            (*cpu_dying)(int cpu);
+       void            (*cpu_dead)(int cpu);
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -165,8 +170,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
        .enabled = 1,
 };
 
-static int x86_perf_event_set_period(struct perf_event *event,
-                            struct hw_perf_event *hwc, int idx);
+static int x86_perf_event_set_period(struct perf_event *event);
 
 /*
  * Generalized hw caching related hw_event table, filled
@@ -189,11 +193,12 @@ static u64 __read_mostly hw_cache_event_ids
  * Returns the delta events processed.
  */
 static u64
-x86_perf_event_update(struct perf_event *event,
-                       struct hw_perf_event *hwc, int idx)
+x86_perf_event_update(struct perf_event *event)
 {
+       struct hw_perf_event *hwc = &event->hw;
        int shift = 64 - x86_pmu.event_bits;
        u64 prev_raw_count, new_raw_count;
+       int idx = hwc->idx;
        s64 delta;
 
        if (idx == X86_PMC_IDX_FIXED_BTS)
@@ -293,7 +298,7 @@ static inline bool bts_available(void)
        return x86_pmu.enable_bts != NULL;
 }
 
-static inline void init_debug_store_on_cpu(int cpu)
+static void init_debug_store_on_cpu(int cpu)
 {
        struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
 
@@ -305,7 +310,7 @@ static inline void init_debug_store_on_cpu(int cpu)
                     (u32)((u64)(unsigned long)ds >> 32));
 }
 
-static inline void fini_debug_store_on_cpu(int cpu)
+static void fini_debug_store_on_cpu(int cpu)
 {
        if (!per_cpu(cpu_hw_events, cpu).ds)
                return;
@@ -638,7 +643,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                if (test_bit(hwc->idx, used_mask))
                        break;
 
-               set_bit(hwc->idx, used_mask);
+               __set_bit(hwc->idx, used_mask);
                if (assign)
                        assign[i] = hwc->idx;
        }
@@ -687,7 +692,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                        if (j == X86_PMC_IDX_MAX)
                                break;
 
-                       set_bit(j, used_mask);
+                       __set_bit(j, used_mask);
 
                        if (assign)
                                assign[i] = j;
@@ -780,6 +785,7 @@ static inline int match_prev_assignment(struct hw_perf_event *hwc,
                hwc->last_tag == cpuc->tags[i];
 }
 
+static int x86_pmu_start(struct perf_event *event);
 static void x86_pmu_stop(struct perf_event *event);
 
 void hw_perf_enable(void)
@@ -796,6 +802,7 @@ void hw_perf_enable(void)
                return;
 
        if (cpuc->n_added) {
+               int n_running = cpuc->n_events - cpuc->n_added;
                /*
                 * apply assignment obtained either from
                 * hw_perf_group_sched_in() or x86_pmu_enable()
@@ -803,8 +810,7 @@ void hw_perf_enable(void)
                 * step1: save events moving to new counters
                 * step2: reprogram moved events into new counters
                 */
-               for (i = 0; i < cpuc->n_events; i++) {
-
+               for (i = 0; i < n_running; i++) {
                        event = cpuc->event_list[i];
                        hwc = &event->hw;
 
@@ -819,29 +825,18 @@ void hw_perf_enable(void)
                                continue;
 
                        x86_pmu_stop(event);
-
-                       hwc->idx = -1;
                }
 
                for (i = 0; i < cpuc->n_events; i++) {
-
                        event = cpuc->event_list[i];
                        hwc = &event->hw;
 
-                       if (hwc->idx == -1) {
+                       if (!match_prev_assignment(hwc, cpuc, i))
                                x86_assign_hw_event(event, cpuc, i);
-                               x86_perf_event_set_period(event, hwc, hwc->idx);
-                       }
-                       /*
-                        * need to mark as active because x86_pmu_disable()
-                        * clear active_mask and events[] yet it preserves
-                        * idx
-                        */
-                       set_bit(hwc->idx, cpuc->active_mask);
-                       cpuc->events[hwc->idx] = event;
+                       else if (i < n_running)
+                               continue;
 
-                       x86_pmu.enable(hwc, hwc->idx);
-                       perf_event_update_userpage(event);
+                       x86_pmu_start(event);
                }
                cpuc->n_added = 0;
                perf_events_lapic_init();
@@ -853,15 +848,16 @@ void hw_perf_enable(void)
        x86_pmu.enable_all();
 }
 
-static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc)
 {
-       (void)checking_wrmsrl(hwc->config_base + idx,
+       (void)checking_wrmsrl(hwc->config_base + hwc->idx,
                              hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
-static inline void x86_pmu_disable_event(struct hw_perf_event *hwc, int idx)
+static inline void x86_pmu_disable_event(struct perf_event *event)
 {
-       (void)checking_wrmsrl(hwc->config_base + idx, hwc->config);
+       struct hw_perf_event *hwc = &event->hw;
+       (void)checking_wrmsrl(hwc->config_base + hwc->idx, hwc->config);
 }
 
 static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
@@ -871,12 +867,12 @@ static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
  * To be called with the event disabled in hw:
  */
 static int
-x86_perf_event_set_period(struct perf_event *event,
-                            struct hw_perf_event *hwc, int idx)
+x86_perf_event_set_period(struct perf_event *event)
 {
+       struct hw_perf_event *hwc = &event->hw;
        s64 left = atomic64_read(&hwc->period_left);
        s64 period = hwc->sample_period;
-       int err, ret = 0;
+       int err, ret = 0, idx = hwc->idx;
 
        if (idx == X86_PMC_IDX_FIXED_BTS)
                return 0;
@@ -922,11 +918,11 @@ x86_perf_event_set_period(struct perf_event *event,
        return ret;
 }
 
-static void x86_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void x86_pmu_enable_event(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        if (cpuc->enabled)
-               __x86_pmu_enable_event(hwc, idx);
+               __x86_pmu_enable_event(&event->hw);
 }
 
 /*
@@ -962,34 +958,32 @@ static int x86_pmu_enable(struct perf_event *event)
        memcpy(cpuc->assign, assign, n*sizeof(int));
 
        cpuc->n_events = n;
-       cpuc->n_added  = n - n0;
+       cpuc->n_added += n - n0;
 
        return 0;
 }
 
 static int x86_pmu_start(struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       int idx = event->hw.idx;
 
-       if (hwc->idx == -1)
+       if (idx == -1)
                return -EAGAIN;
 
-       x86_perf_event_set_period(event, hwc, hwc->idx);
-       x86_pmu.enable(hwc, hwc->idx);
+       x86_perf_event_set_period(event);
+       cpuc->events[idx] = event;
+       __set_bit(idx, cpuc->active_mask);
+       x86_pmu.enable(event);
+       perf_event_update_userpage(event);
 
        return 0;
 }
 
 static void x86_pmu_unthrottle(struct perf_event *event)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (WARN_ON_ONCE(hwc->idx >= X86_PMC_IDX_MAX ||
-                               cpuc->events[hwc->idx] != event))
-               return;
-
-       x86_pmu.enable(hwc, hwc->idx);
+       int ret = x86_pmu_start(event);
+       WARN_ON_ONCE(ret);
 }
 
 void perf_event_print_debug(void)
@@ -1049,18 +1043,16 @@ static void x86_pmu_stop(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
-       /*
-        * Must be done before we disable, otherwise the nmi handler
-        * could reenable again:
-        */
-       clear_bit(idx, cpuc->active_mask);
-       x86_pmu.disable(hwc, idx);
+       if (!__test_and_clear_bit(idx, cpuc->active_mask))
+               return;
+
+       x86_pmu.disable(event);
 
        /*
         * Drain the remaining delta count out of a event
         * that we are disabling:
         */
-       x86_perf_event_update(event, hwc, idx);
+       x86_perf_event_update(event);
 
        cpuc->events[idx] = NULL;
 }
@@ -1108,7 +1100,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
                event = cpuc->events[idx];
                hwc = &event->hw;
 
-               val = x86_perf_event_update(event, hwc, idx);
+               val = x86_perf_event_update(event);
                if (val & (1ULL << (x86_pmu.event_bits - 1)))
                        continue;
 
@@ -1118,11 +1110,11 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
                handled         = 1;
                data.period     = event->hw.last_period;
 
-               if (!x86_perf_event_set_period(event, hwc, idx))
+               if (!x86_perf_event_set_period(event))
                        continue;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       x86_pmu.disable(hwc, idx);
+                       x86_pmu_stop(event);
        }
 
        if (handled)
@@ -1309,7 +1301,7 @@ int hw_perf_group_sched_in(struct perf_event *leader,
        memcpy(cpuc->assign, assign, n0*sizeof(int));
 
        cpuc->n_events  = n0;
-       cpuc->n_added   = n1;
+       cpuc->n_added  += n1;
        ctx->nr_active += n1;
 
        /*
@@ -1337,6 +1329,39 @@ undo:
 #include "perf_event_p6.c"
 #include "perf_event_intel.c"
 
+static int __cpuinit
+x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               if (x86_pmu.cpu_prepare)
+                       x86_pmu.cpu_prepare(cpu);
+               break;
+
+       case CPU_STARTING:
+               if (x86_pmu.cpu_starting)
+                       x86_pmu.cpu_starting(cpu);
+               break;
+
+       case CPU_DYING:
+               if (x86_pmu.cpu_dying)
+                       x86_pmu.cpu_dying(cpu);
+               break;
+
+       case CPU_DEAD:
+               if (x86_pmu.cpu_dead)
+                       x86_pmu.cpu_dead(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 static void __init pmu_check_apic(void)
 {
        if (cpu_has_apic)
@@ -1415,11 +1440,13 @@ void __init init_hw_perf_events(void)
        pr_info("... max period:             %016Lx\n", x86_pmu.max_period);
        pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_events_fixed);
        pr_info("... event mask:             %016Lx\n", perf_event_mask);
+
+       perf_cpu_notifier(x86_pmu_notifier);
 }
 
 static inline void x86_pmu_read(struct perf_event *event)
 {
-       x86_perf_event_update(event, &event->hw, event->hw.idx);
+       x86_perf_event_update(event);
 }
 
 static const struct pmu pmu = {
@@ -1675,28 +1702,16 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
        return entry;
 }
 
-void hw_perf_event_setup_online(int cpu)
+#ifdef CONFIG_EVENT_TRACING
+void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
 {
-       init_debug_store_on_cpu(cpu);
-
-       switch (boot_cpu_data.x86_vendor) {
-       case X86_VENDOR_AMD:
-               amd_pmu_cpu_online(cpu);
-               break;
-       default:
-               return;
-       }
-}
-
-void hw_perf_event_setup_offline(int cpu)
-{
-       init_debug_store_on_cpu(cpu);
-
-       switch (boot_cpu_data.x86_vendor) {
-       case X86_VENDOR_AMD:
-               amd_pmu_cpu_offline(cpu);
-               break;
-       default:
-               return;
-       }
+       regs->ip = ip;
+       /*
+        * perf_arch_fetch_caller_regs adds another call, we need to increment
+        * the skip level
+        */
+       regs->bp = rewind_frame_pointer(skip + 1);
+       regs->cs = __KERNEL_CS;
+       local_save_flags(regs->flags);
 }
+#endif
index 8f3dbfd..573458f 100644 (file)
@@ -271,28 +271,6 @@ done:
        return &emptyconstraint;
 }
 
-static __initconst struct x86_pmu amd_pmu = {
-       .name                   = "AMD",
-       .handle_irq             = x86_pmu_handle_irq,
-       .disable_all            = x86_pmu_disable_all,
-       .enable_all             = x86_pmu_enable_all,
-       .enable                 = x86_pmu_enable_event,
-       .disable                = x86_pmu_disable_event,
-       .eventsel               = MSR_K7_EVNTSEL0,
-       .perfctr                = MSR_K7_PERFCTR0,
-       .event_map              = amd_pmu_event_map,
-       .raw_event              = amd_pmu_raw_event,
-       .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
-       .num_events             = 4,
-       .event_bits             = 48,
-       .event_mask             = (1ULL << 48) - 1,
-       .apic                   = 1,
-       /* use highest bit to detect overflow */
-       .max_period             = (1ULL << 47) - 1,
-       .get_event_constraints  = amd_get_event_constraints,
-       .put_event_constraints  = amd_put_event_constraints
-};
-
 static struct amd_nb *amd_alloc_nb(int cpu, int nb_id)
 {
        struct amd_nb *nb;
@@ -309,7 +287,7 @@ static struct amd_nb *amd_alloc_nb(int cpu, int nb_id)
         * initialize all possible NB constraints
         */
        for (i = 0; i < x86_pmu.num_events; i++) {
-               set_bit(i, nb->event_constraints[i].idxmsk);
+               __set_bit(i, nb->event_constraints[i].idxmsk);
                nb->event_constraints[i].weight = 1;
        }
        return nb;
@@ -378,6 +356,31 @@ static void amd_pmu_cpu_offline(int cpu)
        raw_spin_unlock(&amd_nb_lock);
 }
 
+static __initconst struct x86_pmu amd_pmu = {
+       .name                   = "AMD",
+       .handle_irq             = x86_pmu_handle_irq,
+       .disable_all            = x86_pmu_disable_all,
+       .enable_all             = x86_pmu_enable_all,
+       .enable                 = x86_pmu_enable_event,
+       .disable                = x86_pmu_disable_event,
+       .eventsel               = MSR_K7_EVNTSEL0,
+       .perfctr                = MSR_K7_PERFCTR0,
+       .event_map              = amd_pmu_event_map,
+       .raw_event              = amd_pmu_raw_event,
+       .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
+       .num_events             = 4,
+       .event_bits             = 48,
+       .event_mask             = (1ULL << 48) - 1,
+       .apic                   = 1,
+       /* use highest bit to detect overflow */
+       .max_period             = (1ULL << 47) - 1,
+       .get_event_constraints  = amd_get_event_constraints,
+       .put_event_constraints  = amd_put_event_constraints,
+
+       .cpu_prepare            = amd_pmu_cpu_online,
+       .cpu_dead               = amd_pmu_cpu_offline,
+};
+
 static __init int amd_pmu_init(void)
 {
        /* Performance-monitoring supported from K7 and later: */
@@ -390,11 +393,6 @@ static __init int amd_pmu_init(void)
        memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
               sizeof(hw_cache_event_ids));
 
-       /*
-        * explicitly initialize the boot cpu, other cpus will get
-        * the cpu hotplug callbacks from smp_init()
-        */
-       amd_pmu_cpu_online(smp_processor_id());
        return 0;
 }
 
@@ -405,12 +403,4 @@ static int amd_pmu_init(void)
        return 0;
 }
 
-static void amd_pmu_cpu_online(int cpu)
-{
-}
-
-static void amd_pmu_cpu_offline(int cpu)
-{
-}
-
 #endif
index 44b60c8..84bfde6 100644 (file)
@@ -548,9 +548,9 @@ static inline void intel_pmu_ack_status(u64 ack)
 }
 
 static inline void
-intel_pmu_disable_fixed(struct hw_perf_event *hwc, int __idx)
+intel_pmu_disable_fixed(struct hw_perf_event *hwc)
 {
-       int idx = __idx - X86_PMC_IDX_FIXED;
+       int idx = hwc->idx - X86_PMC_IDX_FIXED;
        u64 ctrl_val, mask;
 
        mask = 0xfULL << (idx * 4);
@@ -621,26 +621,28 @@ static void intel_pmu_drain_bts_buffer(void)
 }
 
 static inline void
-intel_pmu_disable_event(struct hw_perf_event *hwc, int idx)
+intel_pmu_disable_event(struct perf_event *event)
 {
-       if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
                intel_pmu_disable_bts();
                intel_pmu_drain_bts_buffer();
                return;
        }
 
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
-               intel_pmu_disable_fixed(hwc, idx);
+               intel_pmu_disable_fixed(hwc);
                return;
        }
 
-       x86_pmu_disable_event(hwc, idx);
+       x86_pmu_disable_event(event);
 }
 
 static inline void
-intel_pmu_enable_fixed(struct hw_perf_event *hwc, int __idx)
+intel_pmu_enable_fixed(struct hw_perf_event *hwc)
 {
-       int idx = __idx - X86_PMC_IDX_FIXED;
+       int idx = hwc->idx - X86_PMC_IDX_FIXED;
        u64 ctrl_val, bits, mask;
        int err;
 
@@ -670,9 +672,11 @@ intel_pmu_enable_fixed(struct hw_perf_event *hwc, int __idx)
        err = checking_wrmsrl(hwc->config_base, ctrl_val);
 }
 
-static void intel_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void intel_pmu_enable_event(struct perf_event *event)
 {
-       if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
                if (!__get_cpu_var(cpu_hw_events).enabled)
                        return;
 
@@ -681,11 +685,11 @@ static void intel_pmu_enable_event(struct hw_perf_event *hwc, int idx)
        }
 
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
-               intel_pmu_enable_fixed(hwc, idx);
+               intel_pmu_enable_fixed(hwc);
                return;
        }
 
-       __x86_pmu_enable_event(hwc, idx);
+       __x86_pmu_enable_event(hwc);
 }
 
 /*
@@ -694,14 +698,8 @@ static void intel_pmu_enable_event(struct hw_perf_event *hwc, int idx)
  */
 static int intel_pmu_save_and_restart(struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx;
-       int ret;
-
-       x86_perf_event_update(event, hwc, idx);
-       ret = x86_perf_event_set_period(event, hwc, idx);
-
-       return ret;
+       x86_perf_event_update(event);
+       return x86_perf_event_set_period(event);
 }
 
 static void intel_pmu_reset(void)
@@ -745,11 +743,11 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
 
        cpuc = &__get_cpu_var(cpu_hw_events);
 
-       perf_disable();
+       intel_pmu_disable_all();
        intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
        if (!status) {
-               perf_enable();
+               intel_pmu_enable_all();
                return 0;
        }
 
@@ -759,8 +757,7 @@ again:
                WARN_ONCE(1, "perfevents: irq loop stuck!\n");
                perf_event_print_debug();
                intel_pmu_reset();
-               perf_enable();
-               return 1;
+               goto done;
        }
 
        inc_irq_stat(apic_perf_irqs);
@@ -768,7 +765,6 @@ again:
        for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
                struct perf_event *event = cpuc->events[bit];
 
-               clear_bit(bit, (unsigned long *) &status);
                if (!test_bit(bit, cpuc->active_mask))
                        continue;
 
@@ -778,7 +774,7 @@ again:
                data.period = event->hw.last_period;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       intel_pmu_disable_event(&event->hw, bit);
+                       x86_pmu_stop(event);
        }
 
        intel_pmu_ack_status(ack);
@@ -790,8 +786,8 @@ again:
        if (status)
                goto again;
 
-       perf_enable();
-
+done:
+       intel_pmu_enable_all();
        return 1;
 }
 
@@ -870,7 +866,10 @@ static __initconst struct x86_pmu intel_pmu = {
        .max_period             = (1ULL << 31) - 1,
        .enable_bts             = intel_pmu_enable_bts,
        .disable_bts            = intel_pmu_disable_bts,
-       .get_event_constraints  = intel_get_event_constraints
+       .get_event_constraints  = intel_get_event_constraints,
+
+       .cpu_starting           = init_debug_store_on_cpu,
+       .cpu_dying              = fini_debug_store_on_cpu,
 };
 
 static __init int intel_pmu_init(void)
index a4e67b9..a330485 100644 (file)
@@ -77,27 +77,29 @@ static void p6_pmu_enable_all(void)
 }
 
 static inline void
-p6_pmu_disable_event(struct hw_perf_event *hwc, int idx)
+p6_pmu_disable_event(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
        u64 val = P6_NOP_EVENT;
 
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base + idx, val);
+       (void)checking_wrmsrl(hwc->config_base + hwc->idx, val);
 }
 
-static void p6_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void p6_pmu_enable_event(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
        u64 val;
 
        val = hwc->config;
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base + idx, val);
+       (void)checking_wrmsrl(hwc->config_base + hwc->idx, val);
 }
 
 static __initconst struct x86_pmu p6_pmu = {
index 4fd1420..29e5f7c 100644 (file)
@@ -29,4 +29,19 @@ struct stack_frame {
        struct stack_frame *next_frame;
        unsigned long return_address;
 };
+
+static inline unsigned long rewind_frame_pointer(int n)
+{
+       struct stack_frame *frame;
+
+       get_bp(frame);
+
+#ifdef CONFIG_FRAME_POINTER
+       while (n--)
+               frame = frame->next_frame;
 #endif
+
+       return (unsigned long)frame;
+}
+
+#endif /* DUMPSTACK_H */
index d5e2a2e..272c9f1 100644 (file)
@@ -208,7 +208,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                        if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
                                if (ops->stack(data, "IRQ") < 0)
                                        break;
-                               bp = print_context_stack(tinfo, stack, bp,
+                               bp = ops->walk_stack(tinfo, stack, bp,
                                        ops, data, irq_stack_end, &graph);
                                /*
                                 * We link to the next stack (which would be
@@ -229,7 +229,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
        /*
         * This handles the process stack:
         */
-       bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph);
+       bp = ops->walk_stack(tinfo, stack, bp, ops, data, NULL, &graph);
        put_cpu();
 }
 EXPORT_SYMBOL(dump_trace);
index 2ff2b6a..cbe6f39 100644 (file)
@@ -998,6 +998,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        }
 
        if (acpi_video_backlight_support()) {
+               struct backlight_properties props;
                int result;
                static int count = 0;
                char *name;
@@ -1010,12 +1011,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                        return;
 
                sprintf(name, "acpi_video%d", count++);
-               device->backlight = backlight_device_register(name,
-                       NULL, device, &acpi_backlight_ops);
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = device->brightness->count - 3;
+               device->backlight = backlight_device_register(name, NULL, device,
+                                                             &acpi_backlight_ops,
+                                                             &props);
                kfree(name);
                if (IS_ERR(device->backlight))
                        return;
-               device->backlight->props.max_brightness = device->brightness->count-3;
 
                result = sysfs_create_link(&device->backlight->dev.kobj,
                                           &device->dev->dev.kobj, "device");
index 6bd930b..fdc9bcb 100644 (file)
@@ -641,6 +641,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq },     /* MCP67 */
        { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq },     /* MCP67 */
        { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_yesncq },     /* Linux ID */
+       { PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_yesncq },     /* Linux ID */
        { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq },     /* MCP73 */
        { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq },     /* MCP73 */
        { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq },     /* MCP73 */
@@ -2263,7 +2278,7 @@ static void ahci_port_intr(struct ata_port *ap)
        struct ahci_port_priv *pp = ap->private_data;
        struct ahci_host_priv *hpriv = ap->host->private_data;
        int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
-       u32 status, qc_active;
+       u32 status, qc_active = 0;
        int rc;
 
        status = readl(port_mmio + PORT_IRQ_STAT);
@@ -2321,11 +2336,22 @@ static void ahci_port_intr(struct ata_port *ap)
                }
        }
 
-       /* pp->active_link is valid iff any command is in flight */
-       if (ap->qc_active && pp->active_link->sactive)
-               qc_active = readl(port_mmio + PORT_SCR_ACT);
-       else
-               qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+       /* pp->active_link is not reliable once FBS is enabled, both
+        * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
+        * NCQ and non-NCQ commands may be in flight at the same time.
+        */
+       if (pp->fbs_enabled) {
+               if (ap->qc_active) {
+                       qc_active = readl(port_mmio + PORT_SCR_ACT);
+                       qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
+               }
+       } else {
+               /* pp->active_link is valid iff any command is in flight */
+               if (ap->qc_active && pp->active_link->sactive)
+                       qc_active = readl(port_mmio + PORT_SCR_ACT);
+               else
+                       qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+       }
 
        rc = ata_qc_complete_multiple(ap, qc_active);
 
@@ -3022,6 +3048,14 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
                 * to the harddisk doesn't become online after
                 * resuming from STR.  Warn and fail suspend.
+                *
+                * http://bugzilla.kernel.org/show_bug.cgi?id=12276
+                *
+                * Use dates instead of versions to match as HP is
+                * apparently recycling both product and version
+                * strings.
+                *
+                * http://bugzilla.kernel.org/show_bug.cgi?id=15462
                 */
                {
                        .ident = "dv4",
@@ -3030,7 +3064,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                                DMI_MATCH(DMI_PRODUCT_NAME,
                                          "HP Pavilion dv4 Notebook PC"),
                        },
-                       .driver_data = "F.30", /* cutoff BIOS version */
+                       .driver_data = "20090105",      /* F.30 */
                },
                {
                        .ident = "dv5",
@@ -3039,7 +3073,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                                DMI_MATCH(DMI_PRODUCT_NAME,
                                          "HP Pavilion dv5 Notebook PC"),
                        },
-                       .driver_data = "F.16", /* cutoff BIOS version */
+                       .driver_data = "20090506",      /* F.16 */
                },
                {
                        .ident = "dv6",
@@ -3048,7 +3082,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                                DMI_MATCH(DMI_PRODUCT_NAME,
                                          "HP Pavilion dv6 Notebook PC"),
                        },
-                       .driver_data = "F.21",  /* cutoff BIOS version */
+                       .driver_data = "20090423",      /* F.21 */
                },
                {
                        .ident = "HDX18",
@@ -3057,7 +3091,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                                DMI_MATCH(DMI_PRODUCT_NAME,
                                          "HP HDX18 Notebook PC"),
                        },
-                       .driver_data = "F.23",  /* cutoff BIOS version */
+                       .driver_data = "20090430",      /* F.23 */
                },
                /*
                 * Acer eMachines G725 has the same problem.  BIOS
@@ -3065,6 +3099,8 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                 * work.  Inbetween, there are V1.06, V2.06 and V3.03
                 * that we don't have much idea about.  For now,
                 * blacklist anything older than V3.04.
+                *
+                * http://bugzilla.kernel.org/show_bug.cgi?id=15104
                 */
                {
                        .ident = "G725",
@@ -3072,19 +3108,21 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
                                DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
                                DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
                        },
-                       .driver_data = "V3.04", /* cutoff BIOS version */
+                       .driver_data = "20091216",      /* V3.04 */
                },
                { }     /* terminate list */
        };
        const struct dmi_system_id *dmi = dmi_first_match(sysids);
-       const char *ver;
+       int year, month, date;
+       char buf[9];
 
        if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
                return false;
 
-       ver = dmi_get_system_info(DMI_BIOS_VERSION);
+       dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+       snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
 
-       return !ver || strcmp(ver, dmi->driver_data) < 0;
+       return strcmp(buf, dmi->driver_data) < 0;
 }
 
 static bool ahci_broken_online(struct pci_dev *pdev)
index 7fe7c32..23d9505 100644 (file)
@@ -306,11 +306,10 @@ static void vci_bitfield_iterate(struct lanai_dev *lanai,
        const unsigned long *lp,
        void (*func)(struct lanai_dev *,vci_t vci))
 {
-       vci_t vci = find_first_bit(lp, NUM_VCI);
-       while (vci < NUM_VCI) {
+       vci_t vci;
+
+       for_each_set_bit(vci, lp, NUM_VCI)
                func(lanai, vci);
-               vci = find_next_bit(lp, NUM_VCI, vci + 1);
-       }
 }
 
 /* -------------------- BUFFER  UTILITIES: */
index 2f86915..db0848e 100644 (file)
@@ -429,12 +429,16 @@ static inline int memory_fail_init(void)
  * differentiation between which *physical* devices each
  * section belongs to...
  */
+int __weak arch_get_memory_phys_device(unsigned long start_pfn)
+{
+       return 0;
+}
 
 static int add_memory_block(int nid, struct mem_section *section,
-                       unsigned long state, int phys_device,
-                       enum mem_add_context context)
+                       unsigned long state, enum mem_add_context context)
 {
        struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+       unsigned long start_pfn;
        int ret = 0;
 
        if (!mem)
@@ -443,7 +447,8 @@ static int add_memory_block(int nid, struct mem_section *section,
        mem->phys_index = __section_nr(section);
        mem->state = state;
        mutex_init(&mem->state_mutex);
-       mem->phys_device = phys_device;
+       start_pfn = section_nr_to_pfn(mem->phys_index);
+       mem->phys_device = arch_get_memory_phys_device(start_pfn);
 
        ret = register_memory(mem, section);
        if (!ret)
@@ -515,7 +520,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
  */
 int register_new_memory(int nid, struct mem_section *section)
 {
-       return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG);
+       return add_memory_block(nid, section, MEM_OFFLINE, HOTPLUG);
 }
 
 int unregister_memory_section(struct mem_section *section)
@@ -548,7 +553,7 @@ int __init memory_dev_init(void)
                if (!present_section_nr(i))
                        continue;
                err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
-                                       0, BOOT);
+                                      BOOT);
                if (!ret)
                        ret = err;
        }
index e481c59..9c5eea3 100644 (file)
@@ -215,9 +215,7 @@ static void hpet_timer_set_irq(struct hpet_dev *devp)
        else
                v &= ~0xffff;
 
-       for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
-               irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
-
+       for_each_set_bit(irq, &v, HPET_MAX_IRQ) {
                if (irq >= nr_irqs) {
                        irq = HPET_MAX_IRQ;
                        break;
index 20564f8..406228f 100644 (file)
@@ -89,19 +89,21 @@ static struct backlight_ops nv50_bl_ops = {
 
 static int nouveau_nv40_backlight_init(struct drm_device *dev)
 {
+       struct backlight_properties props;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct backlight_device *bd;
 
        if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
                return 0;
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 31;
        bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
-                                      &nv40_bl_ops);
+                                      &nv40_bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
 
        dev_priv->backlight = bd;
-       bd->props.max_brightness = 31;
        bd->props.brightness = nv40_get_intensity(bd);
        backlight_update_status(bd);
 
@@ -110,19 +112,21 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev)
 
 static int nouveau_nv50_backlight_init(struct drm_device *dev)
 {
+       struct backlight_properties props;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct backlight_device *bd;
 
        if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
                return 0;
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 1025;
        bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
-                                      &nv50_bl_ops);
+                                      &nv50_bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
 
        dev_priv->backlight = bd;
-       bd->props.max_brightness = 1025;
        bd->props.brightness = nv50_get_intensity(bd);
        backlight_update_status(bd);
        return 0;
index 368fbb0..2e2aa75 100644 (file)
@@ -1357,6 +1357,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
index cd4ece6..0c4e755 100644 (file)
@@ -564,10 +564,10 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
        struct hid_debug_list *list;
 
        list_for_each_entry(list, &hdev->debug_list, node) {
-               for (i = 0; i <= strlen(buf); i++)
-                       list->hid_debug_buf[(list->tail + i) % (HID_DEBUG_BUFSIZE - 1)] =
+               for (i = 0; i < strlen(buf); i++)
+                       list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
                                buf[i];
-               list->tail = (list->tail + i) % (HID_DEBUG_BUFSIZE - 1);
+               list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
         }
 }
 EXPORT_SYMBOL_GPL(hid_debug_event);
index 72c05f9..797e064 100644 (file)
 
 #define USB_VENDOR_ID_UCLOGIC          0x5543
 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209    0x0042
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U   0x0003
 
 #define USB_VENDOR_ID_VERNIER          0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
index 4a3a94f..c174b64 100644 (file)
@@ -353,7 +353,7 @@ static int magicmouse_probe(struct hid_device *hdev,
                goto err_free;
        }
 
-       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT);
        if (ret) {
                dev_err(&hdev->dev, "magicmouse hw start failed\n");
                goto err_free;
@@ -409,8 +409,11 @@ err_free:
 
 static void magicmouse_remove(struct hid_device *hdev)
 {
+       struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
        hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
+       input_unregister_device(msc->input);
+       kfree(msc);
 }
 
 static const struct hid_device_id magic_mice[] = {
index 3234c72..edcc0c4 100644 (file)
@@ -140,6 +140,9 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                        nd->reading_mt = 1;
                        nd->first_contact_confidence = 0;
                        break;
+               case HID_DG_TIPSWITCH:
+                       /* Prevent emission of touch until validated */
+                       return 1;
                case HID_DG_CONFIDENCE:
                        nd->confidence = value;
                        break;
@@ -259,6 +262,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                                                BTN_TOOL_TRIPLETAP, 0);
                                input_report_key(input,
                                                BTN_TOOL_QUADTAP, 0);
+                               input_report_key(input, BTN_TOUCH, 0);
                        }
                        break;
 
@@ -308,13 +312,20 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 
        list_for_each_entry(hidinput, &hdev->inputs, list) {
+               if (hidinput->report->maxfield < 1)
+                       continue;
+
                input = hidinput->input;
                switch (hidinput->report->field[0]->application) {
                case HID_DG_PEN:
                        input->name = "N-Trig Pen";
                        break;
                case HID_DG_TOUCHSCREEN:
+                       /* These keys are redundant for fingers, clear them
+                        * to prevent incorrect identification */
                        __clear_bit(BTN_TOOL_PEN, input->keybit);
+                       __clear_bit(BTN_TOOL_FINGER, input->keybit);
+                       __clear_bit(BTN_0, input->keybit);
                        /*
                         * A little something special to enable
                         * two and three finger taps.
index 167ea74..c32f32c 100644 (file)
@@ -251,6 +251,8 @@ static const struct hid_device_id tm_devices[] = {
                .driver_data = (unsigned long)ff_rumble },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651),   /* FGT Rumble Force Wheel */
                .driver_data = (unsigned long)ff_rumble },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653),   /* RGT Force Feedback CLUTCH Raging Wheel */
+               .driver_data = (unsigned long)ff_joystick },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654),   /* FGT Force Feedback Wheel */
                .driver_data = (unsigned long)ff_joystick },
        { }
index 7844280..928943c 100644 (file)
@@ -63,6 +63,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
index 71237f8..e78af36 100644 (file)
@@ -613,7 +613,7 @@ static struct scsi_host_template iscsi_iser_sht = {
        .cmd_per_lun            = ISER_DEF_CMD_PER_LUN,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler= iscsi_eh_device_reset,
-       .eh_target_reset_handler= iscsi_eh_target_reset,
+       .eh_target_reset_handler = iscsi_eh_recover_target,
        .target_alloc           = iscsi_target_alloc,
        .use_clustering         = DISABLE_CLUSTERING,
        .proc_name              = "iscsi_iser",
index 6643d65..0220c19 100644 (file)
@@ -1301,7 +1301,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
        }
 
        /* check parameter: CIP Value */
-       if (cmsg->CIPValue > ARRAY_SIZE(cip2bchlc) ||
+       if (cmsg->CIPValue >= ARRAY_SIZE(cip2bchlc) ||
            (cmsg->CIPValue > 0 && cip2bchlc[cmsg->CIPValue].bc == NULL)) {
                dev_notice(cs->dev, "%s: unknown CIP value %d\n",
                           "CONNECT_REQ", cmsg->CIPValue);
@@ -2191,36 +2191,24 @@ static const struct file_operations gigaset_proc_fops = {
        .release        = single_release,
 };
 
-static struct capi_driver capi_driver_gigaset = {
-       .name           = "gigaset",
-       .revision       = "1.0",
-};
-
 /**
- * gigaset_isdn_register() - register to LL
+ * gigaset_isdn_regdev() - register device to LL
  * @cs:                device descriptor structure.
  * @isdnid:    device name.
  *
- * Called by main module to register the device with the LL.
- *
  * Return value: 1 for success, 0 for failure
  */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
 {
        struct gigaset_capi_ctr *iif;
        int rc;
 
-       pr_info("Kernel CAPI interface\n");
-
        iif = kmalloc(sizeof(*iif), GFP_KERNEL);
        if (!iif) {
                pr_err("%s: out of memory\n", __func__);
                return 0;
        }
 
-       /* register driver with CAPI (ToDo: what for?) */
-       register_capi_driver(&capi_driver_gigaset);
-
        /* prepare controller structure */
        iif->ctr.owner         = THIS_MODULE;
        iif->ctr.driverdata    = cs;
@@ -2241,7 +2229,6 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
        rc = attach_capi_ctr(&iif->ctr);
        if (rc) {
                pr_err("attach_capi_ctr failed (%d)\n", rc);
-               unregister_capi_driver(&capi_driver_gigaset);
                kfree(iif);
                return 0;
        }
@@ -2252,17 +2239,36 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
 }
 
 /**
- * gigaset_isdn_unregister() - unregister from LL
+ * gigaset_isdn_unregdev() - unregister device from LL
  * @cs:                device descriptor structure.
- *
- * Called by main module to unregister the device from the LL.
  */
-void gigaset_isdn_unregister(struct cardstate *cs)
+void gigaset_isdn_unregdev(struct cardstate *cs)
 {
        struct gigaset_capi_ctr *iif = cs->iif;
 
        detach_capi_ctr(&iif->ctr);
        kfree(iif);
        cs->iif = NULL;
+}
+
+static struct capi_driver capi_driver_gigaset = {
+       .name           = "gigaset",
+       .revision       = "1.0",
+};
+
+/**
+ * gigaset_isdn_regdrv() - register driver to LL
+ */
+void gigaset_isdn_regdrv(void)
+{
+       pr_info("Kernel CAPI interface\n");
+       register_capi_driver(&capi_driver_gigaset);
+}
+
+/**
+ * gigaset_isdn_unregdrv() - unregister driver from LL
+ */
+void gigaset_isdn_unregdrv(void)
+{
        unregister_capi_driver(&capi_driver_gigaset);
 }
index 85de339..bdc01cb 100644 (file)
@@ -507,7 +507,7 @@ void gigaset_freecs(struct cardstate *cs)
        case 2: /* error in initcshw */
                /* Deregister from LL */
                make_invalid(cs, VALID_ID);
-               gigaset_isdn_unregister(cs);
+               gigaset_isdn_unregdev(cs);
 
                /* fall through */
        case 1: /* error when registering to LL */
@@ -769,7 +769,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
        cs->cmdbytes = 0;
 
        gig_dbg(DEBUG_INIT, "setting up iif");
-       if (!gigaset_isdn_register(cs, modulename)) {
+       if (!gigaset_isdn_regdev(cs, modulename)) {
                pr_err("error registering ISDN device\n");
                goto error;
        }
@@ -1205,11 +1205,13 @@ static int __init gigaset_init_module(void)
                gigaset_debuglevel = DEBUG_DEFAULT;
 
        pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n");
+       gigaset_isdn_regdrv();
        return 0;
 }
 
 static void __exit gigaset_exit_module(void)
 {
+       gigaset_isdn_unregdrv();
 }
 
 module_init(gigaset_init_module);
index 5b27c99..bd0b1ea 100644 (file)
@@ -57,12 +57,20 @@ void gigaset_isdn_stop(struct cardstate *cs)
 {
 }
 
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
 {
-       pr_info("no ISDN subsystem interface\n");
        return 1;
 }
 
-void gigaset_isdn_unregister(struct cardstate *cs)
+void gigaset_isdn_unregdev(struct cardstate *cs)
+{
+}
+
+void gigaset_isdn_regdrv(void)
+{
+       pr_info("no ISDN subsystem interface\n");
+}
+
+void gigaset_isdn_unregdrv(void)
 {
 }
index c8f89b7..206c380 100644 (file)
@@ -1258,14 +1258,10 @@ static void do_action(int action, struct cardstate *cs,
                 * note that bcs may be NULL if no B channel is free
                 */
                at_state2->ConState = 700;
-               kfree(at_state2->str_var[STR_NMBR]);
-               at_state2->str_var[STR_NMBR] = NULL;
-               kfree(at_state2->str_var[STR_ZCPN]);
-               at_state2->str_var[STR_ZCPN] = NULL;
-               kfree(at_state2->str_var[STR_ZBC]);
-               at_state2->str_var[STR_ZBC] = NULL;
-               kfree(at_state2->str_var[STR_ZHLC]);
-               at_state2->str_var[STR_ZHLC] = NULL;
+               for (i = 0; i < STR_NUM; ++i) {
+                       kfree(at_state2->str_var[i]);
+                       at_state2->str_var[i] = NULL;
+               }
                at_state2->int_var[VAR_ZCTP] = -1;
 
                spin_lock_irqsave(&cs->lock, flags);
index 1875ab8..cdd144e 100644 (file)
@@ -675,8 +675,10 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
  */
 
 /* Called from common.c for setting up/shutting down with the ISDN subsystem */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid);
-void gigaset_isdn_unregister(struct cardstate *cs);
+void gigaset_isdn_regdrv(void);
+void gigaset_isdn_unregdrv(void);
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid);
+void gigaset_isdn_unregdev(struct cardstate *cs);
 
 /* Called from hardware module to indicate completion of an skb */
 void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
index f0acb9d..c22e5ac 100644 (file)
@@ -592,15 +592,13 @@ void gigaset_isdn_stop(struct cardstate *cs)
 }
 
 /**
- * gigaset_isdn_register() - register to LL
+ * gigaset_isdn_regdev() - register to LL
  * @cs:                device descriptor structure.
  * @isdnid:    device name.
  *
- * Called by main module to register the device with the LL.
- *
  * Return value: 1 for success, 0 for failure
  */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
 {
        isdn_if *iif;
 
@@ -650,15 +648,29 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
 }
 
 /**
- * gigaset_isdn_unregister() - unregister from LL
+ * gigaset_isdn_unregdev() - unregister device from LL
  * @cs:                device descriptor structure.
- *
- * Called by main module to unregister the device from the LL.
  */
-void gigaset_isdn_unregister(struct cardstate *cs)
+void gigaset_isdn_unregdev(struct cardstate *cs)
 {
        gig_dbg(DEBUG_CMD, "sending UNLOAD");
        gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
        kfree(cs->iif);
        cs->iif = NULL;
 }
+
+/**
+ * gigaset_isdn_regdrv() - register driver to LL
+ */
+void gigaset_isdn_regdrv(void)
+{
+       /* nothing to do */
+}
+
+/**
+ * gigaset_isdn_unregdrv() - unregister driver from LL
+ */
+void gigaset_isdn_unregdrv(void)
+{
+       /* nothing to do */
+}
index a1bcbc2..f0dc6c9 100644 (file)
@@ -628,7 +628,6 @@ void gigaset_if_receive(struct cardstate *cs,
        if (tty == NULL)
                gig_dbg(DEBUG_IF, "receive on closed device");
        else {
-               tty_buffer_request_room(tty, len);
                tty_insert_flip_string(tty, buffer, len);
                tty_flip_buffer_push(tty);
        }
index ae89fb8..341ef17 100644 (file)
@@ -2754,7 +2754,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
                     for (i = 0; i < w; i++)
                       ((T30_INFO   *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i];
                     ((T30_INFO   *)(plci->fax_connect_info_buffer))->head_line_len = 0;
-                    len = offsetof(T30_INFO, station_id) + 20;
+                    len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
                     w = fax_parms[5].length;
                     if (w > 20)
                       w = 20;
@@ -2892,7 +2892,7 @@ static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
     && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
     && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
    {
-            len = offsetof(T30_INFO, station_id) + 20;
+            len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
             if (plci->fax_connect_info_length < len)
             {
               ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
@@ -3802,7 +3802,7 @@ static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
       break;
     }
     ncpi = &m_parms[1];
-    len = offsetof(T30_INFO, station_id) + 20;
+    len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
     if (plci->fax_connect_info_length < len)
     {
       ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
@@ -6830,7 +6830,7 @@ static void nl_ind(PLCI *plci)
         if(((T30_INFO   *)plci->NL.RBuffer->P)->station_id_len)
         {
           plci->ncpi_buffer[len] = 20;
-          for (i = 0; i < 20; i++)
+          for (i = 0; i < T30_MAX_STATION_ID_LENGTH; i++)
             plci->ncpi_buffer[++len] = ((T30_INFO   *)plci->NL.RBuffer->P)->station_id[i];
         }
         if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
@@ -6844,7 +6844,7 @@ static void nl_ind(PLCI *plci)
         if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
           & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
         {
-          i = offsetof(T30_INFO, station_id) + 20 + ((T30_INFO   *)plci->NL.RBuffer->P)->head_line_len;
+          i = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + ((T30_INFO   *)plci->NL.RBuffer->P)->head_line_len;
           while (i < plci->NL.RBuffer->length)
             plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++];
         }
@@ -8400,7 +8400,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp)
         }
       }
       /* copy station id to NLC */
-      for(i=0; i<20; i++)
+      for(i=0; i < T30_MAX_STATION_ID_LENGTH; i++)
       {
         if(i<b3_config_parms[2].length)
         {
@@ -8411,29 +8411,29 @@ static word add_b23(PLCI *plci, API_PARSE *bp)
           ((T30_INFO *)&nlc[1])->station_id[i] = ' ';
         }
       }
-      ((T30_INFO *)&nlc[1])->station_id_len = 20;
+      ((T30_INFO *)&nlc[1])->station_id_len = T30_MAX_STATION_ID_LENGTH;
       /* copy head line to NLC */
       if(b3_config_parms[3].length)
       {
 
-        pos = (byte)(fax_head_line_time (&(((T30_INFO *)&nlc[1])->station_id[20])));
+        pos = (byte)(fax_head_line_time (&(((T30_INFO *)&nlc[1])->station_id[T30_MAX_STATION_ID_LENGTH])));
         if (pos != 0)
         {
           if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE)
             pos = 0;
           else
           {
-            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
-            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
+            nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
             len = (byte)b3_config_parms[2].length;
             if (len > 20)
               len = 20;
             if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE)
             {
               for (i = 0; i < len; i++)
-                ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[2].info)[1+i];
-              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
-              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+                nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ((byte   *)b3_config_parms[2].info)[1+i];
+              nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
+              nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
             }
           }
         }
@@ -8444,9 +8444,8 @@ static word add_b23(PLCI *plci, API_PARSE *bp)
         ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len);
         nlc[0] += (byte)(pos + len);
         for (i = 0; i < len; i++)
-          ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[3].info)[1+i];
-        }
-      else
+          nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] =  ((byte   *)b3_config_parms[3].info)[1+i];
+      } else
         ((T30_INFO *)&nlc[1])->head_line_len = 0;
 
       plci->nsf_control_bits = 0;
@@ -8473,7 +8472,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp)
             fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
           }
             len = nlc[0];
-          pos = offsetof(T30_INFO, station_id) + 20;
+          pos = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
    if (pos < plci->fax_connect_info_length)
    {
      for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
@@ -8525,7 +8524,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp)
       }
 
       PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits);
-      len = offsetof(T30_INFO, station_id) + 20;
+      len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
       for (i = 0; i < len; i++)
         plci->fax_connect_info_buffer[i] = nlc[1+i];
       ((T30_INFO   *) plci->fax_connect_info_buffer)->head_line_len = 0;
index ad36df9..8affba3 100644 (file)
@@ -5265,6 +5265,8 @@ static const struct hm_map hfcm_map[] = {
 /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
                HFC_IO_MODE_EMBSD, XHFC_IRQ},
 /*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
+/*33*/ {VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
+/*34*/ {VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
 };
 
 #undef H
@@ -5300,6 +5302,10 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
                PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
                PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */
+       { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+               0xb761, 0, 0, H(33)}, /* BN2S PCIe */
+       { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+               0xb762, 0, 0, H(34)}, /* BN4S PCIe */
 
        /* Cards with HFC-8S Chip */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
index be787e1..4f541ef 100644 (file)
@@ -143,7 +143,7 @@ pof_handle_data(hysdn_card * card, int datlen)
                                             (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
                                             datlen, boot->pof_recoffset);
 
-                       if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+                       if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0)
                                return (boot->last_error);      /* error writing data */
 
                        if (boot->pof_recoffset + datlen >= boot->pof_reclen)
index e0b6431..505eb64 100644 (file)
@@ -15,6 +15,8 @@ config LEDS_CLASS
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
 
+if LEDS_CLASS
+
 comment "LED drivers"
 
 config LEDS_88PM860X
@@ -26,73 +28,73 @@ config LEDS_88PM860X
 
 config LEDS_ATMEL_PWM
        tristate "LED Support using Atmel PWM outputs"
-       depends on LEDS_CLASS && ATMEL_PWM
+       depends on ATMEL_PWM
        help
          This option enables support for LEDs driven using outputs
          of the dedicated PWM controller found on newer Atmel SOCs.
 
 config LEDS_LOCOMO
        tristate "LED Support for Locomo device"
-       depends on LEDS_CLASS && SHARP_LOCOMO
+       depends on SHARP_LOCOMO
        help
          This option enables support for the LEDs on Sharp Locomo.
          Zaurus models SL-5500 and SL-5600.
 
 config LEDS_MIKROTIK_RB532
        tristate "LED Support for Mikrotik Routerboard 532"
-       depends on LEDS_CLASS && MIKROTIK_RB532
+       depends on MIKROTIK_RB532
        help
          This option enables support for the so called "User LED" of
          Mikrotik's Routerboard 532.
 
 config LEDS_S3C24XX
        tristate "LED Support for Samsung S3C24XX GPIO LEDs"
-       depends on LEDS_CLASS && ARCH_S3C2410
+       depends on ARCH_S3C2410
        help
          This option enables support for LEDs connected to GPIO lines
          on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
 
 config LEDS_AMS_DELTA
        tristate "LED Support for the Amstrad Delta (E3)"
-       depends on LEDS_CLASS && MACH_AMS_DELTA
+       depends on MACH_AMS_DELTA
        help
          This option enables support for the LEDs on Amstrad Delta (E3).
 
 config LEDS_NET48XX
        tristate "LED Support for Soekris net48xx series Error LED"
-       depends on LEDS_CLASS && SCx200_GPIO
+       depends on SCx200_GPIO
        help
          This option enables support for the Soekris net4801 and net4826 error
          LED.
 
 config LEDS_FSG
        tristate "LED Support for the Freecom FSG-3"
-       depends on LEDS_CLASS && MACH_FSG
+       depends on MACH_FSG
        help
          This option enables support for the LEDs on the Freecom FSG-3.
 
 config LEDS_WRAP
        tristate "LED Support for the WRAP series LEDs"
-       depends on LEDS_CLASS && SCx200_GPIO
+       depends on SCx200_GPIO
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
 config LEDS_ALIX2
        tristate "LED Support for ALIX.2 and ALIX.3 series"
-       depends on LEDS_CLASS && X86 && EXPERIMENTAL
+       depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
        help
          This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
          You have to set leds-alix2.force=1 for boards with Award BIOS.
 
 config LEDS_H1940
        tristate "LED Support for iPAQ H1940 device"
-       depends on LEDS_CLASS && ARCH_H1940
+       depends on ARCH_H1940
        help
          This option enables support for the LEDs on the h1940.
 
 config LEDS_COBALT_QUBE
        tristate "LED Support for the Cobalt Qube series front LED"
-       depends on LEDS_CLASS && MIPS_COBALT
+       depends on MIPS_COBALT
        help
          This option enables support for the front LED on Cobalt Qube series
 
@@ -105,7 +107,7 @@ config LEDS_COBALT_RAQ
 
 config LEDS_SUNFIRE
        tristate "LED support for SunFire servers."
-       depends on LEDS_CLASS && SPARC64
+       depends on SPARC64
        select LEDS_TRIGGERS
        help
          This option enables support for the Left, Middle, and Right
@@ -113,14 +115,14 @@ config LEDS_SUNFIRE
 
 config LEDS_HP6XX
        tristate "LED Support for the HP Jornada 6xx"
-       depends on LEDS_CLASS && SH_HP6XX
+       depends on SH_HP6XX
        help
          This option enables LED support for the handheld
          HP Jornada 620/660/680/690.
 
 config LEDS_PCA9532
        tristate "LED driver for PCA9532 dimmer"
-       depends on LEDS_CLASS && I2C && INPUT && EXPERIMENTAL
+       depends on I2C && INPUT && EXPERIMENTAL
        help
          This option enables support for NXP pca9532
          LED controller. It is generally only useful
@@ -128,7 +130,7 @@ config LEDS_PCA9532
 
 config LEDS_GPIO
        tristate "LED Support for GPIO connected LEDs"
-       depends on LEDS_CLASS && GENERIC_GPIO
+       depends on GENERIC_GPIO
        help
          This option enables support for the LEDs connected to GPIO
          outputs. To be useful the particular board must have LEDs
@@ -155,7 +157,7 @@ config LEDS_GPIO_OF
 
 config LEDS_LP3944
        tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
-       depends on LEDS_CLASS && I2C
+       depends on I2C
        help
          This option enables support for LEDs connected to the National
          Semiconductor LP3944 Lighting Management Unit (LMU) also known as
@@ -166,7 +168,7 @@ config LEDS_LP3944
 
 config LEDS_CLEVO_MAIL
        tristate "Mail LED on Clevo notebook"
-       depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI
+       depends on X86 && SERIO_I8042 && DMI
        help
          This driver makes the mail LED accessible from userspace
          programs through the leds subsystem. This LED have three
@@ -196,7 +198,7 @@ config LEDS_CLEVO_MAIL
 
 config LEDS_PCA955X
        tristate "LED Support for PCA955x I2C chips"
-       depends on LEDS_CLASS && I2C
+       depends on I2C
        help
          This option enables support for LEDs connected to PCA955x
          LED driver chips accessed via the I2C bus.  Supported
@@ -204,54 +206,54 @@ config LEDS_PCA955X
 
 config LEDS_WM831X_STATUS
        tristate "LED support for status LEDs on WM831x PMICs"
-       depends on LEDS_CLASS && MFD_WM831X
+       depends on MFD_WM831X
        help
          This option enables support for the status LEDs of the WM831x
           series of PMICs.
 
 config LEDS_WM8350
        tristate "LED Support for WM8350 AudioPlus PMIC"
-       depends on LEDS_CLASS && MFD_WM8350
+       depends on MFD_WM8350
        help
          This option enables support for LEDs driven by the Wolfson
          Microelectronics WM8350 AudioPlus PMIC.
 
 config LEDS_DA903X
        tristate "LED Support for DA9030/DA9034 PMIC"
-       depends on LEDS_CLASS && PMIC_DA903X
+       depends on PMIC_DA903X
        help
          This option enables support for on-chip LED drivers found
          on Dialog Semiconductor DA9030/DA9034 PMICs.
 
 config LEDS_DAC124S085
        tristate "LED Support for DAC124S085 SPI DAC"
-       depends on LEDS_CLASS && SPI
+       depends on SPI
        help
          This option enables support for DAC124S085 SPI DAC from NatSemi,
          which can be used to control up to four LEDs.
 
 config LEDS_PWM
        tristate "PWM driven LED Support"
-       depends on LEDS_CLASS && HAVE_PWM
+       depends on HAVE_PWM
        help
          This option enables support for pwm driven LEDs
 
 config LEDS_REGULATOR
        tristate "REGULATOR driven LED support"
-       depends on LEDS_CLASS && REGULATOR
+       depends on REGULATOR
        help
          This option enables support for regulator driven LEDs.
 
 config LEDS_BD2802
        tristate "LED driver for BD2802 RGB LED"
-       depends on LEDS_CLASS && I2C
+       depends on I2C
        help
          This option enables support for BD2802GU RGB LED driver chips
          accessed via the I2C bus.
 
 config LEDS_INTEL_SS4200
        tristate "LED driver for Intel NAS SS4200 series"
-       depends on LEDS_CLASS && PCI && DMI
+       depends on PCI && DMI
        help
          This option enables support for the Intel SS4200 series of
          Network Attached Storage servers.  You may control the hard
@@ -260,7 +262,7 @@ config LEDS_INTEL_SS4200
 
 config LEDS_LT3593
        tristate "LED driver for LT3593 controllers"
-       depends on LEDS_CLASS && GENERIC_GPIO
+       depends on GENERIC_GPIO
        help
          This option enables support for LEDs driven by a Linear Technology
          LT3593 controller. This controller uses a special one-wire pulse
@@ -268,7 +270,7 @@ config LEDS_LT3593
 
 config LEDS_ADP5520
        tristate "LED Support for ADP5520/ADP5501 PMIC"
-       depends on LEDS_CLASS && PMIC_ADP5520
+       depends on PMIC_ADP5520
        help
          This option enables support for on-chip LED drivers found
          on Analog Devices ADP5520/ADP5501 PMICs.
@@ -276,7 +278,12 @@ config LEDS_ADP5520
          To compile this driver as a module, choose M here: the module will
          be called leds-adp5520.
 
-comment "LED Triggers"
+config LEDS_DELL_NETBOOKS
+       tristate "External LED on Dell Business Netbooks"
+       depends on X86 && ACPI_WMI
+       help
+         This adds support for the Latitude 2100 and similar
+         notebooks that have an external LED.
 
 config LEDS_TRIGGERS
        bool "LED Trigger support"
@@ -285,9 +292,12 @@ config LEDS_TRIGGERS
          These triggers allow kernel events to drive the LEDs and can
          be configured via sysfs. If unsure, say Y.
 
+if LEDS_TRIGGERS
+
+comment "LED Triggers"
+
 config LEDS_TRIGGER_TIMER
        tristate "LED Timer Trigger"
-       depends on LEDS_TRIGGERS
        help
          This allows LEDs to be controlled by a programmable timer
          via sysfs. Some LED hardware can be programmed to start
@@ -298,14 +308,13 @@ config LEDS_TRIGGER_TIMER
 
 config LEDS_TRIGGER_IDE_DISK
        bool "LED IDE Disk Trigger"
-       depends on LEDS_TRIGGERS && IDE_GD_ATA
+       depends on IDE_GD_ATA
        help
          This allows LEDs to be controlled by IDE disk activity.
          If unsure, say Y.
 
 config LEDS_TRIGGER_HEARTBEAT
        tristate "LED Heartbeat Trigger"
-       depends on LEDS_TRIGGERS
        help
          This allows LEDs to be controlled by a CPU load average.
          The flash frequency is a hyperbolic function of the 1-minute
@@ -314,7 +323,6 @@ config LEDS_TRIGGER_HEARTBEAT
 
 config LEDS_TRIGGER_BACKLIGHT
        tristate "LED backlight Trigger"
-       depends on LEDS_TRIGGERS
        help
          This allows LEDs to be controlled as a backlight device: they
          turn off and on when the display is blanked and unblanked.
@@ -323,7 +331,6 @@ config LEDS_TRIGGER_BACKLIGHT
 
 config LEDS_TRIGGER_GPIO
        tristate "LED GPIO Trigger"
-       depends on LEDS_TRIGGERS
        depends on GPIOLIB
        help
          This allows LEDs to be controlled by gpio events. It's good
@@ -336,7 +343,6 @@ config LEDS_TRIGGER_GPIO
 
 config LEDS_TRIGGER_DEFAULT_ON
        tristate "LED Default ON Trigger"
-       depends on LEDS_TRIGGERS
        help
          This allows LEDs to be initialised in the ON state.
          If unsure, say Y.
@@ -344,4 +350,8 @@ config LEDS_TRIGGER_DEFAULT_ON
 comment "iptables trigger is under Netfilter config (LED target)"
        depends on LEDS_TRIGGERS
 
+endif # LEDS_TRIGGERS
+
+endif # LEDS_CLASS
+
 endif # NEW_LEDS
index d76fb32..0cd8b99 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_LEDS_REGULATOR)          += leds-regulator.o
 obj-$(CONFIG_LEDS_INTEL_SS4200)                += leds-ss4200.o
 obj-$(CONFIG_LEDS_LT3593)              += leds-lt3593.o
 obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
+obj-$(CONFIG_LEDS_DELL_NETBOOKS)       += dell-led.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c
new file mode 100644 (file)
index 0000000..ee31089
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * dell_led.c - Dell LED Driver
+ *
+ * Copyright (C) 2010 Dell Inc.
+ * Louis Davis <louis_davis@dell.com>
+ * Jim Dailey <jim_dailey@dell.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.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/leds.h>
+
+MODULE_AUTHOR("Louis Davis/Jim Dailey");
+MODULE_DESCRIPTION("Dell LED Control Driver");
+MODULE_LICENSE("GPL");
+
+#define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396"
+MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
+
+/* Error Result Codes: */
+#define INVALID_DEVICE_ID      250
+#define INVALID_PARAMETER      251
+#define INVALID_BUFFER         252
+#define INTERFACE_ERROR                253
+#define UNSUPPORTED_COMMAND    254
+#define UNSPECIFIED_ERROR      255
+
+/* Device ID */
+#define DEVICE_ID_PANEL_BACK   1
+
+/* LED Commands */
+#define CMD_LED_ON     16
+#define CMD_LED_OFF    17
+#define CMD_LED_BLINK  18
+
+struct bios_args {
+       unsigned char length;
+       unsigned char result_code;
+       unsigned char device_id;
+       unsigned char command;
+       unsigned char on_time;
+       unsigned char off_time;
+};
+
+static int dell_led_perform_fn(u8 length,
+               u8 result_code,
+               u8 device_id,
+               u8 command,
+               u8 on_time,
+               u8 off_time)
+{
+       struct bios_args *bios_return;
+       u8 return_code;
+       union acpi_object *obj;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer input;
+       acpi_status status;
+
+       struct bios_args args;
+       args.length = length;
+       args.result_code = result_code;
+       args.device_id = device_id;
+       args.command = command;
+       args.on_time = on_time;
+       args.off_time = off_time;
+
+       input.length = sizeof(struct bios_args);
+       input.pointer = &args;
+
+       status = wmi_evaluate_method(DELL_LED_BIOS_GUID,
+               1,
+               1,
+               &input,
+               &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return -EINVAL;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return -EINVAL;
+       }
+
+       bios_return = ((struct bios_args *)obj->buffer.pointer);
+       return_code = bios_return->result_code;
+
+       kfree(obj);
+
+       return return_code;
+}
+
+static int led_on(void)
+{
+       return dell_led_perform_fn(3,   /* Length of command */
+               INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
+               DEVICE_ID_PANEL_BACK,   /* Device ID */
+               CMD_LED_ON,             /* Command */
+               0,                      /* not used */
+               0);                     /* not used */
+}
+
+static int led_off(void)
+{
+       return dell_led_perform_fn(3,   /* Length of command */
+               INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
+               DEVICE_ID_PANEL_BACK,   /* Device ID */
+               CMD_LED_OFF,            /* Command */
+               0,                      /* not used */
+               0);                     /* not used */
+}
+
+static int led_blink(unsigned char on_eighths,
+               unsigned char off_eighths)
+{
+       return dell_led_perform_fn(5,   /* Length of command */
+               INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
+               DEVICE_ID_PANEL_BACK,   /* Device ID */
+               CMD_LED_BLINK,          /* Command */
+               on_eighths,             /* blink on in eigths of a second */
+               off_eighths);           /* blink off in eights of a second */
+}
+
+static void dell_led_set(struct led_classdev *led_cdev,
+               enum led_brightness value)
+{
+       if (value == LED_OFF)
+               led_off();
+       else
+               led_on();
+}
+
+static int dell_led_blink(struct led_classdev *led_cdev,
+               unsigned long *delay_on,
+               unsigned long *delay_off)
+{
+       unsigned long on_eighths;
+       unsigned long off_eighths;
+
+       /* The Dell LED delay is based on 125ms intervals.
+          Need to round up to next interval. */
+
+       on_eighths = (*delay_on + 124) / 125;
+       if (0 == on_eighths)
+               on_eighths = 1;
+       if (on_eighths > 255)
+               on_eighths = 255;
+       *delay_on = on_eighths * 125;
+
+       off_eighths = (*delay_off + 124) / 125;
+       if (0 == off_eighths)
+               off_eighths = 1;
+       if (off_eighths > 255)
+               off_eighths = 255;
+       *delay_off = off_eighths * 125;
+
+       led_blink(on_eighths, off_eighths);
+
+       return 0;
+}
+
+static struct led_classdev dell_led = {
+       .name           = "dell::lid",
+       .brightness     = LED_OFF,
+       .max_brightness = 1,
+       .brightness_set = dell_led_set,
+       .blink_set      = dell_led_blink,
+       .flags          = LED_CORE_SUSPENDRESUME,
+};
+
+static int __init dell_led_init(void)
+{
+       int error = 0;
+
+       if (!wmi_has_guid(DELL_LED_BIOS_GUID))
+               return -ENODEV;
+
+       error = led_off();
+       if (error != 0)
+               return -ENODEV;
+
+       return led_classdev_register(NULL, &dell_led);
+}
+
+static void __exit dell_led_exit(void)
+{
+       led_classdev_unregister(&dell_led);
+
+       led_off();
+}
+
+module_init(dell_led_init);
+module_exit(dell_led_exit);
index 782f958..69e7d86 100644 (file)
@@ -72,11 +72,14 @@ static ssize_t led_max_brightness_show(struct device *dev,
        return sprintf(buf, "%u\n", led_cdev->max_brightness);
 }
 
-static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
-static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
+static struct device_attribute led_class_attrs[] = {
+       __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
+       __ATTR(max_brightness, 0644, led_max_brightness_show, NULL),
 #ifdef CONFIG_LEDS_TRIGGERS
-static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+       __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
 #endif
+       __ATTR_NULL,
+};
 
 /**
  * led_classdev_suspend - suspend an led_classdev.
@@ -127,18 +130,11 @@ static int led_resume(struct device *dev)
  */
 int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 {
-       int rc;
-
        led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
                                      "%s", led_cdev->name);
        if (IS_ERR(led_cdev->dev))
                return PTR_ERR(led_cdev->dev);
 
-       /* register the attributes */
-       rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
-       if (rc)
-               goto err_out;
-
 #ifdef CONFIG_LEDS_TRIGGERS
        init_rwsem(&led_cdev->trigger_lock);
 #endif
@@ -150,36 +146,18 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
        if (!led_cdev->max_brightness)
                led_cdev->max_brightness = LED_FULL;
 
-       rc = device_create_file(led_cdev->dev, &dev_attr_max_brightness);
-       if (rc)
-               goto err_out_attr_max;
-
        led_update_brightness(led_cdev);
 
 #ifdef CONFIG_LEDS_TRIGGERS
-       rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
-       if (rc)
-               goto err_out_led_list;
-
        led_trigger_set_default(led_cdev);
 #endif
 
-       printk(KERN_INFO "Registered led device: %s\n",
+       printk(KERN_DEBUG "Registered led device: %s\n",
                        led_cdev->name);
 
        return 0;
-
-#ifdef CONFIG_LEDS_TRIGGERS
-err_out_led_list:
-       device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
-#endif
-err_out_attr_max:
-       device_remove_file(led_cdev->dev, &dev_attr_brightness);
-       list_del(&led_cdev->node);
-err_out:
-       device_unregister(led_cdev->dev);
-       return rc;
 }
+
 EXPORT_SYMBOL_GPL(led_classdev_register);
 
 /**
@@ -190,10 +168,7 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
  */
 void led_classdev_unregister(struct led_classdev *led_cdev)
 {
-       device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
-       device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
-       device_remove_file(led_cdev->dev, &dev_attr_trigger);
        down_write(&led_cdev->trigger_lock);
        if (led_cdev->trigger)
                led_trigger_set(led_cdev, NULL);
@@ -215,6 +190,7 @@ static int __init leds_init(void)
                return PTR_ERR(leds_class);
        leds_class->suspend = led_suspend;
        leds_class->resume = led_resume;
+       leds_class->dev_attrs = led_class_attrs;
        return 0;
 }
 
index e5225d2..0823e26 100644 (file)
@@ -211,7 +211,6 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
                                        const struct of_device_id *match)
 {
        struct device_node *np = ofdev->node, *child;
-       struct gpio_led led;
        struct gpio_led_of_platform_data *pdata;
        int count = 0, ret;
 
@@ -226,8 +225,8 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
        if (!pdata)
                return -ENOMEM;
 
-       memset(&led, 0, sizeof(led));
        for_each_child_of_node(np, child) {
+               struct gpio_led led = {};
                enum of_gpio_flags flags;
                const char *state;
 
index 97f0498..51477ec 100644 (file)
@@ -63,7 +63,7 @@ MODULE_LICENSE("GPL");
 /*
  * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
  */
-static struct pci_device_id ich7_lpc_pci_id[] =
+static const struct pci_device_id ich7_lpc_pci_id[] =
 {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
index 4f3c447..1cec02f 100644 (file)
@@ -144,6 +144,7 @@ void pmu_backlight_set_sleep(int sleep)
 
 void __init pmu_backlight_init()
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
        char name[10];
        int level, autosave;
@@ -161,13 +162,15 @@ void __init pmu_backlight_init()
 
        snprintf(name, sizeof(name), "pmubl");
 
-       bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
+                                      &props);
        if (IS_ERR(bd)) {
                printk(KERN_ERR "PMU Backlight registration failed\n");
                return;
        }
        uses_pmu_bl = 1;
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
 
        level = bd->props.max_brightness;
index af2d39d..bb2a231 100644 (file)
@@ -172,12 +172,14 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
+                * violating it, so limit max_segments to 1 lying within
+                * a single page.
                 */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
+               }
 
                conf->array_sectors += rdev->sectors;
                cnt++;
index 4b323f4..5558ebc 100644 (file)
@@ -301,14 +301,16 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                                          rdev->data_offset << 9);
 
                /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
+                * violating it, so limit ->max_segments to one, lying
+                * within a single page.
                 * (Note: it is very unlikely that a device with
                 * merge_bvec_fn will be involved in multipath.)
                 */
-                       if (q->merge_bvec_fn &&
-                           queue_max_sectors(q) > (PAGE_SIZE>>9))
-                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+                       if (q->merge_bvec_fn) {
+                               blk_queue_max_segments(mddev->queue, 1);
+                               blk_queue_segment_boundary(mddev->queue,
+                                                          PAGE_CACHE_SIZE - 1);
+                       }
 
                        conf->working_disks++;
                        mddev->degraded--;
@@ -476,9 +478,11 @@ static int multipath_run (mddev_t *mddev)
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, not that we ever expect a device with
                 * a merge_bvec_fn to be involved in multipath */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
+               }
 
                if (!test_bit(Faulty, &rdev->flags))
                        conf->working_disks++;
index a1f7147..377cf2a 100644 (file)
@@ -176,14 +176,15 @@ static int create_strip_zones(mddev_t *mddev)
                disk_stack_limits(mddev->gendisk, rdev1->bdev,
                                  rdev1->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
+                * violating it, so limit ->max_segments to 1, lying within
+                * a single page.
                 */
 
-               if (rdev1->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
-
+               if (rdev1->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
+               }
                if (!smallest || (rdev1->sectors < smallest->sectors))
                        smallest = rdev1;
                cnt++;
index 5a06122..f741f77 100644 (file)
@@ -1152,13 +1152,17 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 
                        disk_stack_limits(mddev->gendisk, rdev->bdev,
                                          rdev->data_offset << 9);
-                       /* as we don't honour merge_bvec_fn, we must never risk
-                        * violating it, so limit ->max_sector to one PAGE, as
-                        * a one page request is never in violation.
+                       /* as we don't honour merge_bvec_fn, we must
+                        * never risk violating it, so limit
+                        * ->max_segments to one lying with a single
+                        * page, as a one page request is never in
+                        * violation.
                         */
-                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                           queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                               blk_queue_max_segments(mddev->queue, 1);
+                               blk_queue_segment_boundary(mddev->queue,
+                                                          PAGE_CACHE_SIZE - 1);
+                       }
 
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
@@ -2098,12 +2102,14 @@ static int run(mddev_t *mddev)
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
+                * violating it, so limit ->max_segments to 1 lying within
+                * a single page, as a one page request is never in violation.
                 */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
+               }
        }
 
        mddev->degraded = 0;
index 7584f9a..b4ba41e 100644 (file)
@@ -1155,13 +1155,17 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 
                        disk_stack_limits(mddev->gendisk, rdev->bdev,
                                          rdev->data_offset << 9);
-                       /* as we don't honour merge_bvec_fn, we must never risk
-                        * violating it, so limit ->max_sector to one PAGE, as
-                        * a one page request is never in violation.
+                       /* as we don't honour merge_bvec_fn, we must
+                        * never risk violating it, so limit
+                        * ->max_segments to one lying with a single
+                        * page, as a one page request is never in
+                        * violation.
                         */
-                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                           queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                               blk_queue_max_segments(mddev->queue, 1);
+                               blk_queue_segment_boundary(mddev->queue,
+                                                          PAGE_CACHE_SIZE - 1);
+                       }
 
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
@@ -2255,12 +2259,14 @@ static int run(mddev_t *mddev)
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
+                * violating it, so limit max_segments to 1 lying
+                * within a single page.
                 */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
+               }
 
                disk->head_position = 0;
        }
index 1157d56..42e5ea4 100644 (file)
@@ -457,7 +457,7 @@ config MTD_NAND_NOMADIK
 
 config MTD_NAND_SH_FLCTL
        tristate "Support for NAND on Renesas SuperH FLCTL"
-       depends on MTD_NAND && SUPERH
+       depends on MTD_NAND && (SUPERH || ARCH_SHMOBILE)
        help
          Several Renesas SuperH CPU has FLCTL. This option enables support
          for NAND Flash using FLCTL.
index c592153..50e6259 100644 (file)
@@ -673,7 +673,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                        OPCODE_COMMON_MCC_CREATE, sizeof(*req));
 
-       req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 
        AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
        AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
index ed785a3..6c042a7 100644 (file)
@@ -893,7 +893,6 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
        u16 prod;
        u16 cons;
 
-       barrier(); /* Tell compiler that prod and cons can change */
        prod = fp->tx_bd_prod;
        cons = fp->tx_bd_cons;
 
@@ -963,7 +962,7 @@ static int bnx2x_tx_int(struct bnx2x_fastpath *fp)
         * start_xmit() will miss it and cause the queue to be stopped
         * forever.
         */
-       smp_wmb();
+       smp_mb();
 
        /* TBD need a thresh? */
        if (unlikely(netif_tx_queue_stopped(txq))) {
@@ -11429,9 +11428,12 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
                netif_tx_stop_queue(txq);
-               /* We want bnx2x_tx_int to "see" the updated tx_bd_prod
-                  if we put Tx into XOFF state. */
+
+               /* paired memory barrier is in bnx2x_tx_int(), we have to keep
+                * ordering of set_bit() in netif_tx_stop_queue() and read of
+                * fp->bd_tx_cons */
                smp_mb();
+
                fp->eth_q_stats.driver_xoff++;
                if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
                        netif_tx_wake_queue(txq);
index 8bd086a..2b8edd2 100644 (file)
  *     PHY layer usage
  */
 
-/** Pending Items in this driver:
- * 1. Use Linux cache infrastcture for DMA'ed memory (dma_xxx functions)
- */
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -504,12 +500,6 @@ static unsigned long mdio_max_freq;
 
 /* Cache macros - Packet buffers would be from skb pool which is cached */
 #define EMAC_VIRT_NOCACHE(addr) (addr)
-#define EMAC_CACHE_INVALIDATE(addr, size) \
-       dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE)
-#define EMAC_CACHE_WRITEBACK(addr, size) \
-       dma_cache_maint((void *)addr, size, DMA_TO_DEVICE)
-#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \
-       dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL)
 
 /* DM644x does not have BD's in cached memory - so no cache functions */
 #define BD_CACHE_INVALIDATE(addr, size)
@@ -1235,6 +1225,10 @@ static void emac_txch_teardown(struct emac_priv *priv, u32 ch)
        if (1 == txch->queue_active) {
                curr_bd = txch->active_queue_head;
                while (curr_bd != NULL) {
+                       dma_unmap_single(emac_dev, curr_bd->buff_ptr,
+                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
+                               DMA_TO_DEVICE);
+
                        emac_net_tx_complete(priv, (void __force *)
                                        &curr_bd->buf_token, 1, ch);
                        if (curr_bd != txch->active_queue_tail)
@@ -1327,6 +1321,11 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
                                txch->queue_active = 0; /* end of queue */
                        }
                }
+
+               dma_unmap_single(emac_dev, curr_bd->buff_ptr,
+                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
+                               DMA_TO_DEVICE);
+
                *tx_complete_ptr = (u32) curr_bd->buf_token;
                ++tx_complete_ptr;
                ++tx_complete_cnt;
@@ -1387,8 +1386,8 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
 
        txch->bd_pool_head = curr_bd->next;
        curr_bd->buf_token = buf_list->buf_token;
-       /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */
-       curr_bd->buff_ptr = virt_to_phys(buf_list->data_ptr);
+       curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buf_list->data_ptr,
+                       buf_list->length, DMA_TO_DEVICE);
        curr_bd->off_b_len = buf_list->length;
        curr_bd->h_next = 0;
        curr_bd->next = NULL;
@@ -1468,7 +1467,6 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
        tx_buf.length = skb->len;
        tx_buf.buf_token = (void *)skb;
        tx_buf.data_ptr = skb->data;
-       EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len);
        ndev->trans_start = jiffies;
        ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH);
        if (unlikely(ret_code != 0)) {
@@ -1543,7 +1541,6 @@ static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size,
        p_skb->dev = ndev;
        skb_reserve(p_skb, NET_IP_ALIGN);
        *data_token = (void *) p_skb;
-       EMAC_CACHE_WRITEBACK_INVALIDATE((unsigned long)p_skb->data, buf_size);
        return p_skb->data;
 }
 
@@ -1612,8 +1609,8 @@ static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)
                /* populate the hardware descriptor */
                curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,
                                priv);
-               /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */
-               curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr);
+               curr_bd->buff_ptr = dma_map_single(emac_dev, curr_bd->data_ptr,
+                               rxch->buf_size, DMA_FROM_DEVICE);
                curr_bd->off_b_len = rxch->buf_size;
                curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
 
@@ -1697,6 +1694,12 @@ static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch)
                curr_bd = rxch->active_queue_head;
                while (curr_bd) {
                        if (curr_bd->buf_token) {
+                               dma_unmap_single(&priv->ndev->dev,
+                                       curr_bd->buff_ptr,
+                                       curr_bd->off_b_len
+                                               & EMAC_RX_BD_BUF_SIZE,
+                                       DMA_FROM_DEVICE);
+
                                dev_kfree_skb_any((struct sk_buff *)\
                                                  curr_bd->buf_token);
                        }
@@ -1871,8 +1874,8 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
 
        /* populate the hardware descriptor */
        curr_bd->h_next = 0;
-       /* FIXME buff_ptr = dma_map_single(... buffer ...) */
-       curr_bd->buff_ptr = virt_to_phys(buffer);
+       curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buffer,
+                               rxch->buf_size, DMA_FROM_DEVICE);
        curr_bd->off_b_len = rxch->buf_size;
        curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
        curr_bd->next = NULL;
@@ -1927,7 +1930,6 @@ static int emac_net_rx_cb(struct emac_priv *priv,
        p_skb = (struct sk_buff *)net_pkt_list->pkt_token;
        /* set length of packet */
        skb_put(p_skb, net_pkt_list->pkt_length);
-       EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len);
        p_skb->protocol = eth_type_trans(p_skb, priv->ndev);
        netif_receive_skb(p_skb);
        priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length;
@@ -1990,6 +1992,11 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
                rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;
                rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;
                rx_buf_obj->buf_token = curr_bd->buf_token;
+
+               dma_unmap_single(&priv->ndev->dev, curr_bd->buff_ptr,
+                               curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
+                               DMA_FROM_DEVICE);
+
                curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;
                curr_pkt->num_bufs = 1;
                curr_pkt->pkt_length =
@@ -2820,31 +2827,37 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev)
        return 0;
 }
 
-static
-int davinci_emac_suspend(struct platform_device *pdev, pm_message_t state)
+static int davinci_emac_suspend(struct device *dev)
 {
-       struct net_device *dev = platform_get_drvdata(pdev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
 
-       if (netif_running(dev))
-               emac_dev_stop(dev);
+       if (netif_running(ndev))
+               emac_dev_stop(ndev);
 
        clk_disable(emac_clk);
 
        return 0;
 }
 
-static int davinci_emac_resume(struct platform_device *pdev)
+static int davinci_emac_resume(struct device *dev)
 {
-       struct net_device *dev = platform_get_drvdata(pdev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
 
        clk_enable(emac_clk);
 
-       if (netif_running(dev))
-               emac_dev_open(dev);
+       if (netif_running(ndev))
+               emac_dev_open(ndev);
 
        return 0;
 }
 
+static const struct dev_pm_ops davinci_emac_pm_ops = {
+       .suspend        = davinci_emac_suspend,
+       .resume         = davinci_emac_resume,
+};
+
 /**
  * davinci_emac_driver: EMAC platform driver structure
  */
@@ -2852,11 +2865,10 @@ static struct platform_driver davinci_emac_driver = {
        .driver = {
                .name    = "davinci_emac",
                .owner   = THIS_MODULE,
+               .pm      = &davinci_emac_pm_ops,
        },
        .probe = davinci_emac_probe,
        .remove = __devexit_p(davinci_emac_remove),
-       .suspend = davinci_emac_suspend,
-       .resume = davinci_emac_resume,
 };
 
 /**
index a26ccab..b997e57 100644 (file)
@@ -2858,7 +2858,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        }
        nic->cbs_pool = pci_pool_create(netdev->name,
                           nic->pdev,
-                          nic->params.cbs.count * sizeof(struct cb),
+                          nic->params.cbs.max * sizeof(struct cb),
                           sizeof(u32),
                           0);
        DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
index 551810f..980625f 100644 (file)
@@ -65,7 +65,6 @@
 #undef  CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */
 #define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */
 #endif
-#undef  CONFIG_USE_INTERNAL_TIMER  /* Just cannot make that timer work */
 #define CONFIG_USE_W977_PNP        /* Currently needed */
 #define PIO_MAX_SPEED       115200 
 
@@ -533,25 +532,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
                self->tx_buff.len = skb->len;
                
                mtt = irda_get_mtt(skb);
-#ifdef CONFIG_USE_INTERNAL_TIMER
-               if (mtt > 50) {
-                       /* Adjust for timer resolution */
-                       mtt /= 1000+1;
-
-                       /* Setup timer */
-                       switch_bank(iobase, SET4);
-                       outb(mtt & 0xff, iobase+TMRL);
-                       outb((mtt >> 8) & 0x0f, iobase+TMRH);
-                       
-                       /* Start timer */
-                       outb(IR_MSL_EN_TMR, iobase+IR_MSL);
-                       self->io.direction = IO_XMIT;
-                       
-                       /* Enable timer interrupt */
-                       switch_bank(iobase, SET0);
-                       outb(ICR_ETMRI, iobase+ICR);
-               } else {
-#endif
                        IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);
                        if (mtt)
                                udelay(mtt);
@@ -560,9 +540,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
                        switch_bank(iobase, SET0);
                        outb(ICR_EDMAI, iobase+ICR);
                        w83977af_dma_write(self, iobase);
-#ifdef CONFIG_USE_INTERNAL_TIMER
-               }
-#endif
        } else {
                self->tx_buff.data = self->tx_buff.head;
                self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
@@ -876,20 +853,7 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self)
                        /* Check if we have transferred all data to memory */
                        switch_bank(iobase, SET0);
                        if (inb(iobase+USR) & USR_RDR) {
-#ifdef CONFIG_USE_INTERNAL_TIMER
-                               /* Put this entry back in fifo */
-                               st_fifo->head--;
-                               st_fifo->len++;
-                               st_fifo->entries[st_fifo->head].status = status;
-                               st_fifo->entries[st_fifo->head].len = len;
-                               
-                               /* Restore set register */
-                               outb(set, iobase+SSR);
-                       
-                               return FALSE;   /* I'll be back! */
-#else
                                udelay(80); /* Should be enough!? */
-#endif
                        }
                                                
                        skb = dev_alloc_skb(len+1);
index 7264a3e..0f59099 100644 (file)
@@ -4899,8 +4899,10 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev)
                        struct sk_buff *org_skb = skb;
 
                        skb = dev_alloc_skb(org_skb->len);
-                       if (!skb)
-                               return NETDEV_TX_BUSY;
+                       if (!skb) {
+                               rc = NETDEV_TX_BUSY;
+                               goto unlock;
+                       }
                        skb_copy_and_csum_dev(org_skb, skb->data);
                        org_skb->ip_summed = 0;
                        skb->len = org_skb->len;
@@ -4914,7 +4916,7 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
                rc = NETDEV_TX_BUSY;
        }
-
+unlock:
        spin_unlock_irq(&hw_priv->hwlock);
 
        return rc;
index 676c513..e84dd3e 100644 (file)
@@ -3687,7 +3687,6 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
        if (status != 0) {
                dev_err(&mgp->pdev->dev, "failed reset\n");
                goto abort_with_fw;
-               return;
        }
 
        mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot);
index 992dbff..f4347f8 100644 (file)
@@ -142,7 +142,7 @@ bad_clone_list[] __initdata = {
     {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
     {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
 #ifdef CONFIG_MACH_TX49XX
-    {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */
+    {"RBHMA4X00-RTL8019", "RBHMA4X00-RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */
 #endif
     {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
     {NULL,}
index 9fbb2eb..449a982 100644 (file)
@@ -756,6 +756,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
 
        /* Try to dequeue as many skbs from reorder_q as we can. */
        pppol2tp_recv_dequeue(session);
+       sock_put(sock);
 
        return 0;
 
@@ -772,6 +773,7 @@ discard_bad_csum:
        UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0);
        tunnel->stats.rx_errors++;
        kfree_skb(skb);
+       sock_put(sock);
 
        return 0;
 
@@ -1180,7 +1182,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        /* Calculate UDP checksum if configured to do so */
        if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
                skb->ip_summed = CHECKSUM_NONE;
-       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
+       else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
+                (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {
                skb->ip_summed = CHECKSUM_COMPLETE;
                csum = skb_checksum(skb, 0, udp_len, 0);
                uh->check = csum_tcpudp_magic(inet->inet_saddr,
@@ -1661,6 +1664,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                if (tunnel_sock == NULL)
                        goto end;
 
+               sock_hold(tunnel_sock);
                tunnel = tunnel_sock->sk_user_data;
        } else {
                tunnel = pppol2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel);
index df70657..2eb7f8a 100644 (file)
@@ -5819,10 +5819,8 @@ static void s2io_vpd_read(struct s2io_nic *nic)
                }
        }
 
-       if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
-               memset(nic->product_name, 0, vpd_data[1]);
+       if ((!fail) && (vpd_data[1] < VPD_STRING_LEN))
                memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
-       }
        kfree(vpd_data);
        swstats->mem_freed += 256;
 }
index 32d9356..ba56ce4 100644 (file)
@@ -204,6 +204,14 @@ config USB_NET_DM9601
          This option adds support for Davicom DM9601 based USB 1.1
          10/100 Ethernet adapters.
 
+config USB_NET_SMSC75XX
+       tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
+       depends on USB_USBNET
+       select CRC32
+       help
+         This option adds support for SMSC LAN95XX based USB 2.0
+         Gigabit Ethernet adapters.
+
 config USB_NET_SMSC95XX
        tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"
        depends on USB_USBNET
index e17afb7..82ea629 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_USB_NET_AX8817X) += asix.o
 obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
+obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)   += gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)  += net1080.o
index 6895f15..be0cc99 100644 (file)
@@ -1155,9 +1155,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
 static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
 {
        int result;
-#ifdef CONFIG_HSO_AUTOPM
-       usb_mark_last_busy(urb->dev);
-#endif
        /* We are done with this URB, resubmit it. Prep the USB to wait for
         * another frame */
        usb_fill_bulk_urb(urb, serial->parent->usb,
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
new file mode 100644 (file)
index 0000000..300e3e7
--- /dev/null
@@ -0,0 +1,1288 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007-2010 SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+#include "smsc75xx.h"
+
+#define SMSC_CHIPNAME                  "smsc75xx"
+#define SMSC_DRIVER_VERSION            "1.0.0"
+#define HS_USB_PKT_SIZE                        (512)
+#define FS_USB_PKT_SIZE                        (64)
+#define DEFAULT_HS_BURST_CAP_SIZE      (16 * 1024 + 5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE      (6 * 1024 + 33 * FS_USB_PKT_SIZE)
+#define DEFAULT_BULK_IN_DELAY          (0x00002000)
+#define MAX_SINGLE_PACKET_SIZE         (9000)
+#define LAN75XX_EEPROM_MAGIC           (0x7500)
+#define EEPROM_MAC_OFFSET              (0x01)
+#define DEFAULT_TX_CSUM_ENABLE         (true)
+#define DEFAULT_RX_CSUM_ENABLE         (true)
+#define DEFAULT_TSO_ENABLE             (true)
+#define SMSC75XX_INTERNAL_PHY_ID       (1)
+#define SMSC75XX_TX_OVERHEAD           (8)
+#define MAX_RX_FIFO_SIZE               (20 * 1024)
+#define MAX_TX_FIFO_SIZE               (12 * 1024)
+#define USB_VENDOR_ID_SMSC             (0x0424)
+#define USB_PRODUCT_ID_LAN7500         (0x7500)
+#define USB_PRODUCT_ID_LAN7505         (0x7505)
+
+#define check_warn(ret, fmt, args...) \
+       ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
+
+#define check_warn_return(ret, fmt, args...) \
+       ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } })
+
+#define check_warn_goto_done(ret, fmt, args...) \
+       ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } })
+
+struct smsc75xx_priv {
+       struct usbnet *dev;
+       u32 rfe_ctl;
+       u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
+       bool use_rx_csum;
+       struct mutex dataport_mutex;
+       spinlock_t rfe_ctl_lock;
+       struct work_struct set_multicast;
+};
+
+struct usb_context {
+       struct usb_ctrlrequest req;
+       struct usbnet *dev;
+};
+
+static int turbo_mode = true;
+module_param(turbo_mode, bool, 0644);
+MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+
+static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
+                                         u32 *data)
+{
+       u32 *buf = kmalloc(4, GFP_KERNEL);
+       int ret;
+
+       BUG_ON(!dev);
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+               USB_VENDOR_REQUEST_READ_REGISTER,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+
+       if (unlikely(ret < 0))
+               netdev_warn(dev->net,
+                       "Failed to read register index 0x%08x", index);
+
+       le32_to_cpus(buf);
+       *data = *buf;
+       kfree(buf);
+
+       return ret;
+}
+
+static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
+                                          u32 data)
+{
+       u32 *buf = kmalloc(4, GFP_KERNEL);
+       int ret;
+
+       BUG_ON(!dev);
+
+       if (!buf)
+               return -ENOMEM;
+
+       *buf = data;
+       cpu_to_le32s(buf);
+
+       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+               USB_VENDOR_REQUEST_WRITE_REGISTER,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
+
+       if (unlikely(ret < 0))
+               netdev_warn(dev->net,
+                       "Failed to write register index 0x%08x", index);
+
+       kfree(buf);
+
+       return ret;
+}
+
+/* Loop until the read is completed with timeout
+ * called with phy_mutex held */
+static int smsc75xx_phy_wait_not_busy(struct usbnet *dev)
+{
+       unsigned long start_time = jiffies;
+       u32 val;
+       int ret;
+
+       do {
+               ret = smsc75xx_read_reg(dev, MII_ACCESS, &val);
+               check_warn_return(ret, "Error reading MII_ACCESS");
+
+               if (!(val & MII_ACCESS_BUSY))
+                       return 0;
+       } while (!time_after(jiffies, start_time + HZ));
+
+       return -EIO;
+}
+
+static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       u32 val, addr;
+       int ret;
+
+       mutex_lock(&dev->phy_mutex);
+
+       /* confirm MII not busy */
+       ret = smsc75xx_phy_wait_not_busy(dev);
+       check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read");
+
+       /* set the address, index & direction (read from PHY) */
+       phy_id &= dev->mii.phy_id_mask;
+       idx &= dev->mii.reg_num_mask;
+       addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
+               | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
+               | MII_ACCESS_READ;
+       ret = smsc75xx_write_reg(dev, MII_ACCESS, addr);
+       check_warn_goto_done(ret, "Error writing MII_ACCESS");
+
+       ret = smsc75xx_phy_wait_not_busy(dev);
+       check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx);
+
+       ret = smsc75xx_read_reg(dev, MII_DATA, &val);
+       check_warn_goto_done(ret, "Error reading MII_DATA");
+
+       ret = (u16)(val & 0xFFFF);
+
+done:
+       mutex_unlock(&dev->phy_mutex);
+       return ret;
+}
+
+static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
+                               int regval)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       u32 val, addr;
+       int ret;
+
+       mutex_lock(&dev->phy_mutex);
+
+       /* confirm MII not busy */
+       ret = smsc75xx_phy_wait_not_busy(dev);
+       check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write");
+
+       val = regval;
+       ret = smsc75xx_write_reg(dev, MII_DATA, val);
+       check_warn_goto_done(ret, "Error writing MII_DATA");
+
+       /* set the address, index & direction (write to PHY) */
+       phy_id &= dev->mii.phy_id_mask;
+       idx &= dev->mii.reg_num_mask;
+       addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
+               | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
+               | MII_ACCESS_WRITE;
+       ret = smsc75xx_write_reg(dev, MII_ACCESS, addr);
+       check_warn_goto_done(ret, "Error writing MII_ACCESS");
+
+       ret = smsc75xx_phy_wait_not_busy(dev);
+       check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx);
+
+done:
+       mutex_unlock(&dev->phy_mutex);
+}
+
+static int smsc75xx_wait_eeprom(struct usbnet *dev)
+{
+       unsigned long start_time = jiffies;
+       u32 val;
+       int ret;
+
+       do {
+               ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
+               check_warn_return(ret, "Error reading E2P_CMD");
+
+               if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT))
+                       break;
+               udelay(40);
+       } while (!time_after(jiffies, start_time + HZ));
+
+       if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) {
+               netdev_warn(dev->net, "EEPROM read operation timeout");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev)
+{
+       unsigned long start_time = jiffies;
+       u32 val;
+       int ret;
+
+       do {
+               ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
+               check_warn_return(ret, "Error reading E2P_CMD");
+
+               if (!(val & E2P_CMD_BUSY))
+                       return 0;
+
+               udelay(40);
+       } while (!time_after(jiffies, start_time + HZ));
+
+       netdev_warn(dev->net, "EEPROM is busy");
+       return -EIO;
+}
+
+static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
+                               u8 *data)
+{
+       u32 val;
+       int i, ret;
+
+       BUG_ON(!dev);
+       BUG_ON(!data);
+
+       ret = smsc75xx_eeprom_confirm_not_busy(dev);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < length; i++) {
+               val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR);
+               ret = smsc75xx_write_reg(dev, E2P_CMD, val);
+               check_warn_return(ret, "Error writing E2P_CMD");
+
+               ret = smsc75xx_wait_eeprom(dev);
+               if (ret < 0)
+                       return ret;
+
+               ret = smsc75xx_read_reg(dev, E2P_DATA, &val);
+               check_warn_return(ret, "Error reading E2P_DATA");
+
+               data[i] = val & 0xFF;
+               offset++;
+       }
+
+       return 0;
+}
+
+static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
+                                u8 *data)
+{
+       u32 val;
+       int i, ret;
+
+       BUG_ON(!dev);
+       BUG_ON(!data);
+
+       ret = smsc75xx_eeprom_confirm_not_busy(dev);
+       if (ret)
+               return ret;
+
+       /* Issue write/erase enable command */
+       val = E2P_CMD_BUSY | E2P_CMD_EWEN;
+       ret = smsc75xx_write_reg(dev, E2P_CMD, val);
+       check_warn_return(ret, "Error writing E2P_CMD");
+
+       ret = smsc75xx_wait_eeprom(dev);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < length; i++) {
+
+               /* Fill data register */
+               val = data[i];
+               ret = smsc75xx_write_reg(dev, E2P_DATA, val);
+               check_warn_return(ret, "Error writing E2P_DATA");
+
+               /* Send "write" command */
+               val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR);
+               ret = smsc75xx_write_reg(dev, E2P_CMD, val);
+               check_warn_return(ret, "Error writing E2P_CMD");
+
+               ret = smsc75xx_wait_eeprom(dev);
+               if (ret < 0)
+                       return ret;
+
+               offset++;
+       }
+
+       return 0;
+}
+
+static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev)
+{
+       int i, ret;
+
+       for (i = 0; i < 100; i++) {
+               u32 dp_sel;
+               ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
+               check_warn_return(ret, "Error reading DP_SEL");
+
+               if (dp_sel & DP_SEL_DPRDY)
+                       return 0;
+
+               udelay(40);
+       }
+
+       netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out");
+
+       return -EIO;
+}
+
+static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr,
+                                  u32 length, u32 *buf)
+{
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       u32 dp_sel;
+       int i, ret;
+
+       mutex_lock(&pdata->dataport_mutex);
+
+       ret = smsc75xx_dataport_wait_not_busy(dev);
+       check_warn_goto_done(ret, "smsc75xx_dataport_write busy on entry");
+
+       ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
+       check_warn_goto_done(ret, "Error reading DP_SEL");
+
+       dp_sel &= ~DP_SEL_RSEL;
+       dp_sel |= ram_select;
+       ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel);
+       check_warn_goto_done(ret, "Error writing DP_SEL");
+
+       for (i = 0; i < length; i++) {
+               ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i);
+               check_warn_goto_done(ret, "Error writing DP_ADDR");
+
+               ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]);
+               check_warn_goto_done(ret, "Error writing DP_DATA");
+
+               ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE);
+               check_warn_goto_done(ret, "Error writing DP_CMD");
+
+               ret = smsc75xx_dataport_wait_not_busy(dev);
+               check_warn_goto_done(ret, "smsc75xx_dataport_write timeout");
+       }
+
+done:
+       mutex_unlock(&pdata->dataport_mutex);
+       return ret;
+}
+
+/* returns hash bit number for given MAC address */
+static u32 smsc75xx_hash(char addr[ETH_ALEN])
+{
+       return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff;
+}
+
+static void smsc75xx_deferred_multicast_write(struct work_struct *param)
+{
+       struct smsc75xx_priv *pdata =
+               container_of(param, struct smsc75xx_priv, set_multicast);
+       struct usbnet *dev = pdata->dev;
+       int ret;
+
+       netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x",
+               pdata->rfe_ctl);
+
+       smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN,
+               DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table);
+
+       ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+       check_warn(ret, "Error writing RFE_CRL");
+}
+
+static void smsc75xx_set_multicast(struct net_device *netdev)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
+
+       pdata->rfe_ctl &=
+               ~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF);
+       pdata->rfe_ctl |= RFE_CTL_AB;
+
+       for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++)
+               pdata->multicast_hash_table[i] = 0;
+
+       if (dev->net->flags & IFF_PROMISC) {
+               netif_dbg(dev, drv, dev->net, "promiscuous mode enabled");
+               pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU;
+       } else if (dev->net->flags & IFF_ALLMULTI) {
+               netif_dbg(dev, drv, dev->net, "receive all multicast enabled");
+               pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF;
+       } else if (!netdev_mc_empty(dev->net)) {
+               struct dev_mc_list *mc_list;
+
+               netif_dbg(dev, drv, dev->net, "receive multicast hash filter");
+
+               pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF;
+
+               netdev_for_each_mc_addr(mc_list, netdev) {
+                       u32 bitnum = smsc75xx_hash(mc_list->dmi_addr);
+                       pdata->multicast_hash_table[bitnum / 32] |=
+                               (1 << (bitnum % 32));
+               }
+       } else {
+               netif_dbg(dev, drv, dev->net, "receive own packets only");
+               pdata->rfe_ctl |= RFE_CTL_DPF;
+       }
+
+       spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
+
+       /* defer register writes to a sleepable context */
+       schedule_work(&pdata->set_multicast);
+}
+
+static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
+                                           u16 lcladv, u16 rmtadv)
+{
+       u32 flow = 0, fct_flow = 0;
+       int ret;
+
+       if (duplex == DUPLEX_FULL) {
+               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+               if (cap & FLOW_CTRL_TX) {
+                       flow = (FLOW_TX_FCEN | 0xFFFF);
+                       /* set fct_flow thresholds to 20% and 80% */
+                       fct_flow = (8 << 8) | 32;
+               }
+
+               if (cap & FLOW_CTRL_RX)
+                       flow |= FLOW_RX_FCEN;
+
+               netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s",
+                       (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+                       (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+       } else {
+               netif_dbg(dev, link, dev->net, "half duplex");
+       }
+
+       ret = smsc75xx_write_reg(dev, FLOW, flow);
+       check_warn_return(ret, "Error writing FLOW");
+
+       ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow);
+       check_warn_return(ret, "Error writing FCT_FLOW");
+
+       return 0;
+}
+
+static int smsc75xx_link_reset(struct usbnet *dev)
+{
+       struct mii_if_info *mii = &dev->mii;
+       struct ethtool_cmd ecmd;
+       u16 lcladv, rmtadv;
+       int ret;
+
+       /* clear interrupt status */
+       ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
+       check_warn_return(ret, "Error reading PHY_INT_SRC");
+
+       ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
+       check_warn_return(ret, "Error writing INT_STS");
+
+       mii_check_media(mii, 1, 1);
+       mii_ethtool_gset(&dev->mii, &ecmd);
+       lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
+       rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
+
+       netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x"
+               " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+
+       return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
+}
+
+static void smsc75xx_status(struct usbnet *dev, struct urb *urb)
+{
+       u32 intdata;
+
+       if (urb->actual_length != 4) {
+               netdev_warn(dev->net,
+                       "unexpected urb length %d", urb->actual_length);
+               return;
+       }
+
+       memcpy(&intdata, urb->transfer_buffer, 4);
+       le32_to_cpus(&intdata);
+
+       netif_dbg(dev, link, dev->net, "intdata: 0x%08X", intdata);
+
+       if (intdata & INT_ENP_PHY_INT)
+               usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+       else
+               netdev_warn(dev->net,
+                       "unexpected interrupt, intdata=0x%08X", intdata);
+}
+
+/* Enable or disable Rx checksum offload engine */
+static int smsc75xx_set_rx_csum_offload(struct usbnet *dev)
+{
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
+
+       if (pdata->use_rx_csum)
+               pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
+       else
+               pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
+
+       spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
+
+       ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+       check_warn_return(ret, "Error writing RFE_CTL");
+
+       return 0;
+}
+
+static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)
+{
+       return MAX_EEPROM_SIZE;
+}
+
+static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev,
+                                      struct ethtool_eeprom *ee, u8 *data)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       ee->magic = LAN75XX_EEPROM_MAGIC;
+
+       return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data);
+}
+
+static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
+                                      struct ethtool_eeprom *ee, u8 *data)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       if (ee->magic != LAN75XX_EEPROM_MAGIC) {
+               netdev_warn(dev->net,
+                       "EEPROM: magic value mismatch: 0x%x", ee->magic);
+               return -EINVAL;
+       }
+
+       return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
+}
+
+static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+
+       return pdata->use_rx_csum;
+}
+
+static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+
+       pdata->use_rx_csum = !!val;
+
+       return smsc75xx_set_rx_csum_offload(dev);
+}
+
+static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data)
+{
+       if (data)
+               netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+       else
+               netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+       return 0;
+}
+
+static const struct ethtool_ops smsc75xx_ethtool_ops = {
+       .get_link       = usbnet_get_link,
+       .nway_reset     = usbnet_nway_reset,
+       .get_drvinfo    = usbnet_get_drvinfo,
+       .get_msglevel   = usbnet_get_msglevel,
+       .set_msglevel   = usbnet_set_msglevel,
+       .get_settings   = usbnet_get_settings,
+       .set_settings   = usbnet_set_settings,
+       .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len,
+       .get_eeprom     = smsc75xx_ethtool_get_eeprom,
+       .set_eeprom     = smsc75xx_ethtool_set_eeprom,
+       .get_tx_csum    = ethtool_op_get_tx_csum,
+       .set_tx_csum    = ethtool_op_set_tx_hw_csum,
+       .get_rx_csum    = smsc75xx_ethtool_get_rx_csum,
+       .set_rx_csum    = smsc75xx_ethtool_set_rx_csum,
+       .get_tso        = ethtool_op_get_tso,
+       .set_tso        = smsc75xx_ethtool_set_tso,
+};
+
+static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       if (!netif_running(netdev))
+               return -EINVAL;
+
+       return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static void smsc75xx_init_mac_address(struct usbnet *dev)
+{
+       /* try reading mac address from EEPROM */
+       if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+                       dev->net->dev_addr) == 0) {
+               if (is_valid_ether_addr(dev->net->dev_addr)) {
+                       /* eeprom values are valid so use them */
+                       netif_dbg(dev, ifup, dev->net,
+                               "MAC address read from EEPROM");
+                       return;
+               }
+       }
+
+       /* no eeprom, or eeprom values are invalid. generate random MAC */
+       random_ether_addr(dev->net->dev_addr);
+       netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr");
+}
+
+static int smsc75xx_set_mac_address(struct usbnet *dev)
+{
+       u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
+               dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
+       u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
+
+       int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi);
+       check_warn_return(ret, "Failed to write RX_ADDRH: %d", ret);
+
+       ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo);
+       check_warn_return(ret, "Failed to write RX_ADDRL: %d", ret);
+
+       addr_hi |= ADDR_FILTX_FB_VALID;
+       ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi);
+       check_warn_return(ret, "Failed to write ADDR_FILTX: %d", ret);
+
+       ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo);
+       check_warn_return(ret, "Failed to write ADDR_FILTX+4: %d", ret);
+
+       return 0;
+}
+
+static int smsc75xx_phy_initialize(struct usbnet *dev)
+{
+       int bmcr, timeout = 0;
+
+       /* Initialize MII structure */
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = smsc75xx_mdio_read;
+       dev->mii.mdio_write = smsc75xx_mdio_write;
+       dev->mii.phy_id_mask = 0x1f;
+       dev->mii.reg_num_mask = 0x1f;
+       dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID;
+
+       /* reset phy and wait for reset to complete */
+       smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+
+       do {
+               msleep(10);
+               bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
+               check_warn_return(bmcr, "Error reading MII_BMCR");
+               timeout++;
+       } while ((bmcr & MII_BMCR) && (timeout < 100));
+
+       if (timeout >= 100) {
+               netdev_warn(dev->net, "timeout on PHY Reset");
+               return -EIO;
+       }
+
+       smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+               ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
+               ADVERTISE_PAUSE_ASYM);
+
+       /* read to clear */
+       smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
+       check_warn_return(bmcr, "Error reading PHY_INT_SRC");
+
+       smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
+               PHY_INT_MASK_DEFAULT);
+       mii_nway_restart(&dev->mii);
+
+       netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
+       return 0;
+}
+
+static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
+{
+       int ret = 0;
+       u32 buf;
+       bool rxenabled;
+
+       ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
+       check_warn_return(ret, "Failed to read MAC_RX: %d", ret);
+
+       rxenabled = ((buf & MAC_RX_RXEN) != 0);
+
+       if (rxenabled) {
+               buf &= ~MAC_RX_RXEN;
+               ret = smsc75xx_write_reg(dev, MAC_RX, buf);
+               check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
+       }
+
+       /* add 4 to size for FCS */
+       buf &= ~MAC_RX_MAX_SIZE;
+       buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE);
+
+       ret = smsc75xx_write_reg(dev, MAC_RX, buf);
+       check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
+
+       if (rxenabled) {
+               buf |= MAC_RX_RXEN;
+               ret = smsc75xx_write_reg(dev, MAC_RX, buf);
+               check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
+       }
+
+       return 0;
+}
+
+static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu);
+       check_warn_return(ret, "Failed to set mac rx frame length");
+
+       return usbnet_change_mtu(netdev, new_mtu);
+}
+
+static int smsc75xx_reset(struct usbnet *dev)
+{
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       u32 buf;
+       int ret = 0, timeout;
+
+       netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset");
+
+       ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+       check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+
+       buf |= HW_CFG_LRST;
+
+       ret = smsc75xx_write_reg(dev, HW_CFG, buf);
+       check_warn_return(ret, "Failed to write HW_CFG: %d", ret);
+
+       timeout = 0;
+       do {
+               msleep(10);
+               ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+               check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+               timeout++;
+       } while ((buf & HW_CFG_LRST) && (timeout < 100));
+
+       if (timeout >= 100) {
+               netdev_warn(dev->net, "timeout on completion of Lite Reset");
+               return -EIO;
+       }
+
+       netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY");
+
+       ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
+       check_warn_return(ret, "Failed to read PMT_CTL: %d", ret);
+
+       buf |= PMT_CTL_PHY_RST;
+
+       ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
+       check_warn_return(ret, "Failed to write PMT_CTL: %d", ret);
+
+       timeout = 0;
+       do {
+               msleep(10);
+               ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
+               check_warn_return(ret, "Failed to read PMT_CTL: %d", ret);
+               timeout++;
+       } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
+
+       if (timeout >= 100) {
+               netdev_warn(dev->net, "timeout waiting for PHY Reset");
+               return -EIO;
+       }
+
+       netif_dbg(dev, ifup, dev->net, "PHY reset complete");
+
+       smsc75xx_init_mac_address(dev);
+
+       ret = smsc75xx_set_mac_address(dev);
+       check_warn_return(ret, "Failed to set mac address");
+
+       netif_dbg(dev, ifup, dev->net, "MAC Address: %pM", dev->net->dev_addr);
+
+       ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+       check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x", buf);
+
+       buf |= HW_CFG_BIR;
+
+       ret = smsc75xx_write_reg(dev, HW_CFG, buf);
+       check_warn_return(ret, "Failed to write HW_CFG: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+       check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after "
+                       "writing HW_CFG_BIR: 0x%08x", buf);
+
+       if (!turbo_mode) {
+               buf = 0;
+               dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+       } else if (dev->udev->speed == USB_SPEED_HIGH) {
+               buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+               dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+       } else {
+               buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+               dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+       }
+
+       netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld",
+               (ulong)dev->rx_urb_size);
+
+       ret = smsc75xx_write_reg(dev, BURST_CAP, buf);
+       check_warn_return(ret, "Failed to write BURST_CAP: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, BURST_CAP, &buf);
+       check_warn_return(ret, "Failed to read BURST_CAP: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net,
+               "Read Value from BURST_CAP after writing: 0x%08x", buf);
+
+       ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
+       check_warn_return(ret, "Failed to write BULK_IN_DLY: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf);
+       check_warn_return(ret, "Failed to read BULK_IN_DLY: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net,
+               "Read Value from BULK_IN_DLY after writing: 0x%08x", buf);
+
+       if (turbo_mode) {
+               ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+               check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+
+               netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf);
+
+               buf |= (HW_CFG_MEF | HW_CFG_BCE);
+
+               ret = smsc75xx_write_reg(dev, HW_CFG, buf);
+               check_warn_return(ret, "Failed to write HW_CFG: %d", ret);
+
+               ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
+               check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
+
+               netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf);
+       }
+
+       /* set FIFO sizes */
+       buf = (MAX_RX_FIFO_SIZE - 512) / 512;
+       ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf);
+       check_warn_return(ret, "Failed to write FCT_RX_FIFO_END: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x", buf);
+
+       buf = (MAX_TX_FIFO_SIZE - 512) / 512;
+       ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf);
+       check_warn_return(ret, "Failed to write FCT_TX_FIFO_END: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x", buf);
+
+       ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
+       check_warn_return(ret, "Failed to write INT_STS: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, ID_REV, &buf);
+       check_warn_return(ret, "Failed to read ID_REV: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf);
+
+       /* Configure GPIO pins as LED outputs */
+       ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf);
+       check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret);
+
+       buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL);
+       buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL;
+
+       ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf);
+       check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret);
+
+       ret = smsc75xx_write_reg(dev, FLOW, 0);
+       check_warn_return(ret, "Failed to write FLOW: %d", ret);
+
+       ret = smsc75xx_write_reg(dev, FCT_FLOW, 0);
+       check_warn_return(ret, "Failed to write FCT_FLOW: %d", ret);
+
+       /* Don't need rfe_ctl_lock during initialisation */
+       ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
+       check_warn_return(ret, "Failed to read RFE_CTL: %d", ret);
+
+       pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF;
+
+       ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+       check_warn_return(ret, "Failed to write RFE_CTL: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
+       check_warn_return(ret, "Failed to read RFE_CTL: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl);
+
+       /* Enable or disable checksum offload engines */
+       ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE);
+       ret = smsc75xx_set_rx_csum_offload(dev);
+       check_warn_return(ret, "Failed to set rx csum offload: %d", ret);
+
+       smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE);
+
+       smsc75xx_set_multicast(dev->net);
+
+       ret = smsc75xx_phy_initialize(dev);
+       check_warn_return(ret, "Failed to initialize PHY: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf);
+       check_warn_return(ret, "Failed to read INT_EP_CTL: %d", ret);
+
+       /* enable PHY interrupts */
+       buf |= INT_ENP_PHY_INT;
+
+       ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf);
+       check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret);
+
+       ret = smsc75xx_read_reg(dev, MAC_TX, &buf);
+       check_warn_return(ret, "Failed to read MAC_TX: %d", ret);
+
+       buf |= MAC_TX_TXEN;
+
+       ret = smsc75xx_write_reg(dev, MAC_TX, buf);
+       check_warn_return(ret, "Failed to write MAC_TX: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x", buf);
+
+       ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf);
+       check_warn_return(ret, "Failed to read FCT_TX_CTL: %d", ret);
+
+       buf |= FCT_TX_CTL_EN;
+
+       ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf);
+       check_warn_return(ret, "Failed to write FCT_TX_CTL: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x", buf);
+
+       ret = smsc75xx_set_rx_max_frame_length(dev, 1514);
+       check_warn_return(ret, "Failed to set max rx frame length");
+
+       ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
+       check_warn_return(ret, "Failed to read MAC_RX: %d", ret);
+
+       buf |= MAC_RX_RXEN;
+
+       ret = smsc75xx_write_reg(dev, MAC_RX, buf);
+       check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x", buf);
+
+       ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf);
+       check_warn_return(ret, "Failed to read FCT_RX_CTL: %d", ret);
+
+       buf |= FCT_RX_CTL_EN;
+
+       ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf);
+       check_warn_return(ret, "Failed to write FCT_RX_CTL: %d", ret);
+
+       netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x", buf);
+
+       netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0");
+       return 0;
+}
+
+static const struct net_device_ops smsc75xx_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = smsc75xx_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = smsc75xx_ioctl,
+       .ndo_set_multicast_list = smsc75xx_set_multicast,
+};
+
+static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct smsc75xx_priv *pdata = NULL;
+       int ret;
+
+       printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
+
+       ret = usbnet_get_endpoints(dev, intf);
+       check_warn_return(ret, "usbnet_get_endpoints failed: %d", ret);
+
+       dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
+               GFP_KERNEL);
+
+       pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       if (!pdata) {
+               netdev_warn(dev->net, "Unable to allocate smsc75xx_priv");
+               return -ENOMEM;
+       }
+
+       pdata->dev = dev;
+
+       spin_lock_init(&pdata->rfe_ctl_lock);
+       mutex_init(&pdata->dataport_mutex);
+
+       INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
+
+       pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+
+       /* We have to advertise SG otherwise TSO cannot be enabled */
+       dev->net->features |= NETIF_F_SG;
+
+       /* Init all registers */
+       ret = smsc75xx_reset(dev);
+
+       dev->net->netdev_ops = &smsc75xx_netdev_ops;
+       dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
+       dev->net->flags |= IFF_MULTICAST;
+       dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
+       return 0;
+}
+
+static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+       if (pdata) {
+               netif_dbg(dev, ifdown, dev->net, "free pdata");
+               kfree(pdata);
+               pdata = NULL;
+               dev->data[0] = 0;
+       }
+}
+
+static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,
+                                    u32 rx_cmd_b)
+{
+       if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
+               skb->ip_summed = CHECKSUM_NONE;
+       } else {
+               skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT));
+               skb->ip_summed = CHECKSUM_COMPLETE;
+       }
+}
+
+static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+
+       while (skb->len > 0) {
+               u32 rx_cmd_a, rx_cmd_b, align_count, size;
+               struct sk_buff *ax_skb;
+               unsigned char *packet;
+
+               memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a));
+               le32_to_cpus(&rx_cmd_a);
+               skb_pull(skb, 4);
+
+               memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b));
+               le32_to_cpus(&rx_cmd_b);
+               skb_pull(skb, 4 + NET_IP_ALIGN);
+
+               packet = skb->data;
+
+               /* get the packet length */
+               size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN;
+               align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
+
+               if (unlikely(rx_cmd_a & RX_CMD_A_RED)) {
+                       netif_dbg(dev, rx_err, dev->net,
+                               "Error rx_cmd_a=0x%08x", rx_cmd_a);
+                       dev->net->stats.rx_errors++;
+                       dev->net->stats.rx_dropped++;
+
+                       if (rx_cmd_a & RX_CMD_A_FCS)
+                               dev->net->stats.rx_crc_errors++;
+                       else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))
+                               dev->net->stats.rx_frame_errors++;
+               } else {
+                       /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
+                       if (unlikely(size > (ETH_FRAME_LEN + 12))) {
+                               netif_dbg(dev, rx_err, dev->net,
+                                       "size err rx_cmd_a=0x%08x", rx_cmd_a);
+                               return 0;
+                       }
+
+                       /* last frame in this batch */
+                       if (skb->len == size) {
+                               if (pdata->use_rx_csum)
+                                       smsc75xx_rx_csum_offload(skb, rx_cmd_a,
+                                               rx_cmd_b);
+                               else
+                                       skb->ip_summed = CHECKSUM_NONE;
+
+                               skb_trim(skb, skb->len - 4); /* remove fcs */
+                               skb->truesize = size + sizeof(struct sk_buff);
+
+                               return 1;
+                       }
+
+                       ax_skb = skb_clone(skb, GFP_ATOMIC);
+                       if (unlikely(!ax_skb)) {
+                               netdev_warn(dev->net, "Error allocating skb");
+                               return 0;
+                       }
+
+                       ax_skb->len = size;
+                       ax_skb->data = packet;
+                       skb_set_tail_pointer(ax_skb, size);
+
+                       if (pdata->use_rx_csum)
+                               smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a,
+                                       rx_cmd_b);
+                       else
+                               ax_skb->ip_summed = CHECKSUM_NONE;
+
+                       skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
+                       ax_skb->truesize = size + sizeof(struct sk_buff);
+
+                       usbnet_skb_return(dev, ax_skb);
+               }
+
+               skb_pull(skb, size);
+
+               /* padding bytes before the next frame starts */
+               if (skb->len)
+                       skb_pull(skb, align_count);
+       }
+
+       if (unlikely(skb->len < 0)) {
+               netdev_warn(dev->net, "invalid rx length<0 %d", skb->len);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
+                                        struct sk_buff *skb, gfp_t flags)
+{
+       u32 tx_cmd_a, tx_cmd_b;
+
+       skb_linearize(skb);
+
+       if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
+               struct sk_buff *skb2 =
+                       skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
+               dev_kfree_skb_any(skb);
+               skb = skb2;
+               if (!skb)
+                       return NULL;
+       }
+
+       tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE;
+
+       if (skb_is_gso(skb)) {
+               u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN);
+               tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS;
+
+               tx_cmd_a |= TX_CMD_A_LSO;
+       } else {
+               tx_cmd_b = 0;
+       }
+
+       skb_push(skb, 4);
+       cpu_to_le32s(&tx_cmd_b);
+       memcpy(skb->data, &tx_cmd_b, 4);
+
+       skb_push(skb, 4);
+       cpu_to_le32s(&tx_cmd_a);
+       memcpy(skb->data, &tx_cmd_a, 4);
+
+       return skb;
+}
+
+static const struct driver_info smsc75xx_info = {
+       .description    = "smsc75xx USB 2.0 Gigabit Ethernet",
+       .bind           = smsc75xx_bind,
+       .unbind         = smsc75xx_unbind,
+       .link_reset     = smsc75xx_link_reset,
+       .reset          = smsc75xx_reset,
+       .rx_fixup       = smsc75xx_rx_fixup,
+       .tx_fixup       = smsc75xx_tx_fixup,
+       .status         = smsc75xx_status,
+       .flags          = FLAG_ETHER | FLAG_SEND_ZLP,
+};
+
+static const struct usb_device_id products[] = {
+       {
+               /* SMSC7500 USB Gigabit Ethernet Device */
+               USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500),
+               .driver_info = (unsigned long) &smsc75xx_info,
+       },
+       {
+               /* SMSC7500 USB Gigabit Ethernet Device */
+               USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505),
+               .driver_info = (unsigned long) &smsc75xx_info,
+       },
+       { },            /* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver smsc75xx_driver = {
+       .name           = SMSC_CHIPNAME,
+       .id_table       = products,
+       .probe          = usbnet_probe,
+       .suspend        = usbnet_suspend,
+       .resume         = usbnet_resume,
+       .disconnect     = usbnet_disconnect,
+};
+
+static int __init smsc75xx_init(void)
+{
+       return usb_register(&smsc75xx_driver);
+}
+module_init(smsc75xx_init);
+
+static void __exit smsc75xx_exit(void)
+{
+       usb_deregister(&smsc75xx_driver);
+}
+module_exit(smsc75xx_exit);
+
+MODULE_AUTHOR("Nancy Lin");
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
+MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h
new file mode 100644 (file)
index 0000000..16e98c7
--- /dev/null
@@ -0,0 +1,421 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007-2010 SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *****************************************************************************/
+
+#ifndef _SMSC75XX_H
+#define _SMSC75XX_H
+
+/* Tx command words */
+#define TX_CMD_A_LSO                   (0x08000000)
+#define TX_CMD_A_IPE                   (0x04000000)
+#define TX_CMD_A_TPE                   (0x02000000)
+#define TX_CMD_A_IVTG                  (0x01000000)
+#define TX_CMD_A_RVTG                  (0x00800000)
+#define TX_CMD_A_FCS                   (0x00400000)
+#define TX_CMD_A_LEN                   (0x000FFFFF)
+
+#define TX_CMD_B_MSS                   (0x3FFF0000)
+#define TX_CMD_B_MSS_SHIFT             (16)
+#define TX_MSS_MIN                     ((u16)8)
+#define TX_CMD_B_VTAG                  (0x0000FFFF)
+
+/* Rx command words */
+#define RX_CMD_A_ICE                   (0x80000000)
+#define RX_CMD_A_TCE                   (0x40000000)
+#define RX_CMD_A_IPV                   (0x20000000)
+#define RX_CMD_A_PID                   (0x18000000)
+#define RX_CMD_A_PID_NIP               (0x00000000)
+#define RX_CMD_A_PID_TCP               (0x08000000)
+#define RX_CMD_A_PID_UDP               (0x10000000)
+#define RX_CMD_A_PID_PP                        (0x18000000)
+#define RX_CMD_A_PFF                   (0x04000000)
+#define RX_CMD_A_BAM                   (0x02000000)
+#define RX_CMD_A_MAM                   (0x01000000)
+#define RX_CMD_A_FVTG                  (0x00800000)
+#define RX_CMD_A_RED                   (0x00400000)
+#define RX_CMD_A_RWT                   (0x00200000)
+#define RX_CMD_A_RUNT                  (0x00100000)
+#define RX_CMD_A_LONG                  (0x00080000)
+#define RX_CMD_A_RXE                   (0x00040000)
+#define RX_CMD_A_DRB                   (0x00020000)
+#define RX_CMD_A_FCS                   (0x00010000)
+#define RX_CMD_A_UAM                   (0x00008000)
+#define RX_CMD_A_LCSM                  (0x00004000)
+#define RX_CMD_A_LEN                   (0x00003FFF)
+
+#define RX_CMD_B_CSUM                  (0xFFFF0000)
+#define RX_CMD_B_CSUM_SHIFT            (16)
+#define RX_CMD_B_VTAG                  (0x0000FFFF)
+
+/* SCSRs */
+#define ID_REV                         (0x0000)
+
+#define FPGA_REV                       (0x0004)
+
+#define BOND_CTL                       (0x0008)
+
+#define INT_STS                                (0x000C)
+#define INT_STS_RDFO_INT               (0x00400000)
+#define INT_STS_TXE_INT                        (0x00200000)
+#define INT_STS_MACRTO_INT             (0x00100000)
+#define INT_STS_TX_DIS_INT             (0x00080000)
+#define INT_STS_RX_DIS_INT             (0x00040000)
+#define INT_STS_PHY_INT_               (0x00020000)
+#define INT_STS_MAC_ERR_INT            (0x00008000)
+#define INT_STS_TDFU                   (0x00004000)
+#define INT_STS_TDFO                   (0x00002000)
+#define INT_STS_GPIOS                  (0x00000FFF)
+#define INT_STS_CLEAR_ALL              (0xFFFFFFFF)
+
+#define HW_CFG                         (0x0010)
+#define HW_CFG_SMDET_STS               (0x00008000)
+#define HW_CFG_SMDET_EN                        (0x00004000)
+#define HW_CFG_EEM                     (0x00002000)
+#define HW_CFG_RST_PROTECT             (0x00001000)
+#define HW_CFG_PORT_SWAP               (0x00000800)
+#define HW_CFG_PHY_BOOST               (0x00000600)
+#define HW_CFG_PHY_BOOST_NORMAL                (0x00000000)
+#define HW_CFG_PHY_BOOST_4             (0x00002000)
+#define HW_CFG_PHY_BOOST_8             (0x00004000)
+#define HW_CFG_PHY_BOOST_12            (0x00006000)
+#define HW_CFG_LEDB                    (0x00000100)
+#define HW_CFG_BIR                     (0x00000080)
+#define HW_CFG_SBP                     (0x00000040)
+#define HW_CFG_IME                     (0x00000020)
+#define HW_CFG_MEF                     (0x00000010)
+#define HW_CFG_ETC                     (0x00000008)
+#define HW_CFG_BCE                     (0x00000004)
+#define HW_CFG_LRST                    (0x00000002)
+#define HW_CFG_SRST                    (0x00000001)
+
+#define PMT_CTL                                (0x0014)
+#define PMT_CTL_PHY_PWRUP              (0x00000400)
+#define PMT_CTL_RES_CLR_WKP_EN         (0x00000100)
+#define PMT_CTL_DEV_RDY                        (0x00000080)
+#define PMT_CTL_SUS_MODE               (0x00000060)
+#define PMT_CTL_SUS_MODE_0             (0x00000000)
+#define PMT_CTL_SUS_MODE_1             (0x00000020)
+#define PMT_CTL_SUS_MODE_2             (0x00000040)
+#define PMT_CTL_SUS_MODE_3             (0x00000060)
+#define PMT_CTL_PHY_RST                        (0x00000010)
+#define PMT_CTL_WOL_EN                 (0x00000008)
+#define PMT_CTL_ED_EN                  (0x00000004)
+#define PMT_CTL_WUPS                   (0x00000003)
+#define PMT_CTL_WUPS_NO                        (0x00000000)
+#define PMT_CTL_WUPS_ED                        (0x00000001)
+#define PMT_CTL_WUPS_WOL               (0x00000002)
+#define PMT_CTL_WUPS_MULTI             (0x00000003)
+
+#define LED_GPIO_CFG                   (0x0018)
+#define LED_GPIO_CFG_LED2_FUN_SEL      (0x80000000)
+#define LED_GPIO_CFG_LED10_FUN_SEL     (0x40000000)
+#define LED_GPIO_CFG_LEDGPIO_EN                (0x0000F000)
+#define LED_GPIO_CFG_LEDGPIO_EN_0      (0x00001000)
+#define LED_GPIO_CFG_LEDGPIO_EN_1      (0x00002000)
+#define LED_GPIO_CFG_LEDGPIO_EN_2      (0x00004000)
+#define LED_GPIO_CFG_LEDGPIO_EN_3      (0x00008000)
+#define LED_GPIO_CFG_GPBUF             (0x00000F00)
+#define LED_GPIO_CFG_GPBUF_0           (0x00000100)
+#define LED_GPIO_CFG_GPBUF_1           (0x00000200)
+#define LED_GPIO_CFG_GPBUF_2           (0x00000400)
+#define LED_GPIO_CFG_GPBUF_3           (0x00000800)
+#define LED_GPIO_CFG_GPDIR             (0x000000F0)
+#define LED_GPIO_CFG_GPDIR_0           (0x00000010)
+#define LED_GPIO_CFG_GPDIR_1           (0x00000020)
+#define LED_GPIO_CFG_GPDIR_2           (0x00000040)
+#define LED_GPIO_CFG_GPDIR_3           (0x00000080)
+#define LED_GPIO_CFG_GPDATA            (0x0000000F)
+#define LED_GPIO_CFG_GPDATA_0          (0x00000001)
+#define LED_GPIO_CFG_GPDATA_1          (0x00000002)
+#define LED_GPIO_CFG_GPDATA_2          (0x00000004)
+#define LED_GPIO_CFG_GPDATA_3          (0x00000008)
+
+#define GPIO_CFG                       (0x001C)
+#define GPIO_CFG_SHIFT                 (24)
+#define GPIO_CFG_GPEN                  (0xFF000000)
+#define GPIO_CFG_GPBUF                 (0x00FF0000)
+#define GPIO_CFG_GPDIR                 (0x0000FF00)
+#define GPIO_CFG_GPDATA                        (0x000000FF)
+
+#define GPIO_WAKE                      (0x0020)
+#define GPIO_WAKE_PHY_LINKUP_EN                (0x80000000)
+#define GPIO_WAKE_POL                  (0x0FFF0000)
+#define GPIO_WAKE_POL_SHIFT            (16)
+#define GPIO_WAKE_WK                   (0x00000FFF)
+
+#define DP_SEL                         (0x0024)
+#define DP_SEL_DPRDY                   (0x80000000)
+#define DP_SEL_RSEL                    (0x0000000F)
+#define DP_SEL_URX                     (0x00000000)
+#define DP_SEL_VHF                     (0x00000001)
+#define DP_SEL_VHF_HASH_LEN            (16)
+#define DP_SEL_VHF_VLAN_LEN            (128)
+#define DP_SEL_LSO_HEAD                        (0x00000002)
+#define DP_SEL_FCT_RX                  (0x00000003)
+#define DP_SEL_FCT_TX                  (0x00000004)
+#define DP_SEL_DESCRIPTOR              (0x00000005)
+#define DP_SEL_WOL                     (0x00000006)
+
+#define DP_CMD                         (0x0028)
+#define DP_CMD_WRITE                   (0x01)
+#define DP_CMD_READ                    (0x00)
+
+#define DP_ADDR                                (0x002C)
+
+#define DP_DATA                                (0x0030)
+
+#define BURST_CAP                      (0x0034)
+#define BURST_CAP_MASK                 (0x0000000F)
+
+#define INT_EP_CTL                     (0x0038)
+#define INT_EP_CTL_INTEP_ON            (0x80000000)
+#define INT_EP_CTL_RDFO_EN             (0x00400000)
+#define INT_EP_CTL_TXE_EN              (0x00200000)
+#define INT_EP_CTL_MACROTO_EN          (0x00100000)
+#define INT_EP_CTL_TX_DIS_EN           (0x00080000)
+#define INT_EP_CTL_RX_DIS_EN           (0x00040000)
+#define INT_EP_CTL_PHY_EN_             (0x00020000)
+#define INT_EP_CTL_MAC_ERR_EN          (0x00008000)
+#define INT_EP_CTL_TDFU_EN             (0x00004000)
+#define INT_EP_CTL_TDFO_EN             (0x00002000)
+#define INT_EP_CTL_RX_FIFO_EN          (0x00001000)
+#define INT_EP_CTL_GPIOX_EN            (0x00000FFF)
+
+#define BULK_IN_DLY                    (0x003C)
+#define BULK_IN_DLY_MASK               (0xFFFF)
+
+#define E2P_CMD                                (0x0040)
+#define E2P_CMD_BUSY                   (0x80000000)
+#define E2P_CMD_MASK                   (0x70000000)
+#define E2P_CMD_READ                   (0x00000000)
+#define E2P_CMD_EWDS                   (0x10000000)
+#define E2P_CMD_EWEN                   (0x20000000)
+#define E2P_CMD_WRITE                  (0x30000000)
+#define E2P_CMD_WRAL                   (0x40000000)
+#define E2P_CMD_ERASE                  (0x50000000)
+#define E2P_CMD_ERAL                   (0x60000000)
+#define E2P_CMD_RELOAD                 (0x70000000)
+#define E2P_CMD_TIMEOUT                        (0x00000400)
+#define E2P_CMD_LOADED                 (0x00000200)
+#define E2P_CMD_ADDR                   (0x000001FF)
+
+#define MAX_EEPROM_SIZE                        (512)
+
+#define E2P_DATA                       (0x0044)
+#define E2P_DATA_MASK_                 (0x000000FF)
+
+#define RFE_CTL                                (0x0060)
+#define RFE_CTL_TCPUDP_CKM             (0x00001000)
+#define RFE_CTL_IP_CKM                 (0x00000800)
+#define RFE_CTL_AB                     (0x00000400)
+#define RFE_CTL_AM                     (0x00000200)
+#define RFE_CTL_AU                     (0x00000100)
+#define RFE_CTL_VS                     (0x00000080)
+#define RFE_CTL_UF                     (0x00000040)
+#define RFE_CTL_VF                     (0x00000020)
+#define RFE_CTL_SPF                    (0x00000010)
+#define RFE_CTL_MHF                    (0x00000008)
+#define RFE_CTL_DHF                    (0x00000004)
+#define RFE_CTL_DPF                    (0x00000002)
+#define RFE_CTL_RST_RF                 (0x00000001)
+
+#define VLAN_TYPE                      (0x0064)
+#define VLAN_TYPE_MASK                 (0x0000FFFF)
+
+#define FCT_RX_CTL                     (0x0090)
+#define FCT_RX_CTL_EN                  (0x80000000)
+#define FCT_RX_CTL_RST                 (0x40000000)
+#define FCT_RX_CTL_SBF                 (0x02000000)
+#define FCT_RX_CTL_OVERFLOW            (0x01000000)
+#define FCT_RX_CTL_FRM_DROP            (0x00800000)
+#define FCT_RX_CTL_RX_NOT_EMPTY                (0x00400000)
+#define FCT_RX_CTL_RX_EMPTY            (0x00200000)
+#define FCT_RX_CTL_RX_DISABLED         (0x00100000)
+#define FCT_RX_CTL_RXUSED              (0x0000FFFF)
+
+#define FCT_TX_CTL                     (0x0094)
+#define FCT_TX_CTL_EN                  (0x80000000)
+#define FCT_TX_CTL_RST                 (0x40000000)
+#define FCT_TX_CTL_TX_NOT_EMPTY                (0x00400000)
+#define FCT_TX_CTL_TX_EMPTY            (0x00200000)
+#define FCT_TX_CTL_TX_DISABLED         (0x00100000)
+#define FCT_TX_CTL_TXUSED              (0x0000FFFF)
+
+#define FCT_RX_FIFO_END                        (0x0098)
+#define FCT_RX_FIFO_END_MASK           (0x0000007F)
+
+#define FCT_TX_FIFO_END                        (0x009C)
+#define FCT_TX_FIFO_END_MASK           (0x0000003F)
+
+#define FCT_FLOW                       (0x00A0)
+#define FCT_FLOW_THRESHOLD_OFF         (0x00007F00)
+#define FCT_FLOW_THRESHOLD_OFF_SHIFT   (8)
+#define FCT_FLOW_THRESHOLD_ON          (0x0000007F)
+
+/* MAC CSRs */
+#define MAC_CR                         (0x100)
+#define MAC_CR_ADP                     (0x00002000)
+#define MAC_CR_ADD                     (0x00001000)
+#define MAC_CR_ASD                     (0x00000800)
+#define MAC_CR_INT_LOOP                        (0x00000400)
+#define MAC_CR_BOLMT                   (0x000000C0)
+#define MAC_CR_FDPX                    (0x00000008)
+#define MAC_CR_CFG                     (0x00000006)
+#define MAC_CR_CFG_10                  (0x00000000)
+#define MAC_CR_CFG_100                 (0x00000002)
+#define MAC_CR_CFG_1000                        (0x00000004)
+#define MAC_CR_RST                     (0x00000001)
+
+#define MAC_RX                         (0x104)
+#define MAC_RX_MAX_SIZE                        (0x3FFF0000)
+#define MAC_RX_MAX_SIZE_SHIFT          (16)
+#define MAC_RX_FCS_STRIP               (0x00000010)
+#define MAC_RX_FSE                     (0x00000004)
+#define MAC_RX_RXD                     (0x00000002)
+#define MAC_RX_RXEN                    (0x00000001)
+
+#define MAC_TX                         (0x108)
+#define MAC_TX_BFCS                    (0x00000004)
+#define MAC_TX_TXD                     (0x00000002)
+#define MAC_TX_TXEN                    (0x00000001)
+
+#define FLOW                           (0x10C)
+#define FLOW_FORCE_FC                  (0x80000000)
+#define FLOW_TX_FCEN                   (0x40000000)
+#define FLOW_RX_FCEN                   (0x20000000)
+#define FLOW_FPF                       (0x10000000)
+#define FLOW_PAUSE_TIME                        (0x0000FFFF)
+
+#define RAND_SEED                      (0x110)
+#define RAND_SEED_MASK                 (0x0000FFFF)
+
+#define ERR_STS                                (0x114)
+#define ERR_STS_FCS_ERR                        (0x00000100)
+#define ERR_STS_LFRM_ERR               (0x00000080)
+#define ERR_STS_RUNT_ERR               (0x00000040)
+#define ERR_STS_COLLISION_ERR          (0x00000010)
+#define ERR_STS_ALIGN_ERR              (0x00000008)
+#define ERR_STS_URUN_ERR               (0x00000004)
+
+#define RX_ADDRH                       (0x118)
+#define RX_ADDRH_MASK                  (0x0000FFFF)
+
+#define RX_ADDRL                       (0x11C)
+
+#define MII_ACCESS                     (0x120)
+#define MII_ACCESS_PHY_ADDR            (0x0000F800)
+#define MII_ACCESS_PHY_ADDR_SHIFT      (11)
+#define MII_ACCESS_REG_ADDR            (0x000007C0)
+#define MII_ACCESS_REG_ADDR_SHIFT      (6)
+#define MII_ACCESS_READ                        (0x00000000)
+#define MII_ACCESS_WRITE               (0x00000002)
+#define MII_ACCESS_BUSY                        (0x00000001)
+
+#define MII_DATA                       (0x124)
+#define MII_DATA_MASK                  (0x0000FFFF)
+
+#define WUCSR                          (0x140)
+#define WUCSR_PFDA_FR                  (0x00000080)
+#define WUCSR_WUFR                     (0x00000040)
+#define WUCSR_MPR                      (0x00000020)
+#define WUCSR_BCAST_FR                 (0x00000010)
+#define WUCSR_PFDA_EN                  (0x00000008)
+#define WUCSR_WUEN                     (0x00000004)
+#define WUCSR_MPEN                     (0x00000002)
+#define WUCSR_BCST_EN                  (0x00000001)
+
+#define WUF_CFGX                       (0x144)
+#define WUF_CFGX_EN                    (0x80000000)
+#define WUF_CFGX_ATYPE                 (0x03000000)
+#define WUF_CFGX_ATYPE_UNICAST         (0x00000000)
+#define WUF_CFGX_ATYPE_MULTICAST       (0x02000000)
+#define WUF_CFGX_ATYPE_ALL             (0x03000000)
+#define WUF_CFGX_PATTERN_OFFSET                (0x007F0000)
+#define WUF_CFGX_PATTERN_OFFSET_SHIFT  (16)
+#define WUF_CFGX_CRC16                 (0x0000FFFF)
+#define WUF_NUM                                (8)
+
+#define WUF_MASKX                      (0x170)
+#define WUF_MASKX_AVALID               (0x80000000)
+#define WUF_MASKX_ATYPE                        (0x40000000)
+
+#define ADDR_FILTX                     (0x300)
+#define ADDR_FILTX_FB_VALID            (0x80000000)
+#define ADDR_FILTX_FB_TYPE             (0x40000000)
+#define ADDR_FILTX_FB_ADDRHI           (0x0000FFFF)
+#define ADDR_FILTX_SB_ADDRLO           (0xFFFFFFFF)
+
+#define WUCSR2                         (0x500)
+#define WUCSR2_NS_RCD                  (0x00000040)
+#define WUCSR2_ARP_RCD                 (0x00000020)
+#define WUCSR2_TCPSYN_RCD              (0x00000010)
+#define WUCSR2_NS_OFFLOAD              (0x00000004)
+#define WUCSR2_ARP_OFFLOAD             (0x00000002)
+#define WUCSR2_TCPSYN_OFFLOAD          (0x00000001)
+
+#define WOL_FIFO_STS                   (0x504)
+
+#define IPV6_ADDRX                     (0x510)
+
+#define IPV4_ADDRX                     (0x590)
+
+
+/* Vendor-specific PHY Definitions */
+
+/* Mode Control/Status Register */
+#define PHY_MODE_CTRL_STS              (17)
+#define MODE_CTRL_STS_EDPWRDOWN                ((u16)0x2000)
+#define MODE_CTRL_STS_ENERGYON         ((u16)0x0002)
+
+#define PHY_INT_SRC                    (29)
+#define PHY_INT_SRC_ENERGY_ON          ((u16)0x0080)
+#define PHY_INT_SRC_ANEG_COMP          ((u16)0x0040)
+#define PHY_INT_SRC_REMOTE_FAULT       ((u16)0x0020)
+#define PHY_INT_SRC_LINK_DOWN          ((u16)0x0010)
+
+#define PHY_INT_MASK                   (30)
+#define PHY_INT_MASK_ENERGY_ON         ((u16)0x0080)
+#define PHY_INT_MASK_ANEG_COMP         ((u16)0x0040)
+#define PHY_INT_MASK_REMOTE_FAULT      ((u16)0x0020)
+#define PHY_INT_MASK_LINK_DOWN         ((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT           (PHY_INT_MASK_ANEG_COMP | \
+                                        PHY_INT_MASK_LINK_DOWN)
+
+#define PHY_SPECIAL                    (31)
+#define PHY_SPECIAL_SPD                        ((u16)0x001C)
+#define PHY_SPECIAL_SPD_10HALF         ((u16)0x0004)
+#define PHY_SPECIAL_SPD_10FULL         ((u16)0x0014)
+#define PHY_SPECIAL_SPD_100HALF                ((u16)0x0008)
+#define PHY_SPECIAL_SPD_100FULL                ((u16)0x0018)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER      0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER       0xA1
+#define USB_VENDOR_REQUEST_GET_STATS           0xA2
+
+/* Interrupt Endpoint status word bitfields */
+#define INT_ENP_RDFO_INT               ((u32)BIT(22))
+#define INT_ENP_TXE_INT                        ((u32)BIT(21))
+#define INT_ENP_TX_DIS_INT             ((u32)BIT(19))
+#define INT_ENP_RX_DIS_INT             ((u32)BIT(18))
+#define INT_ENP_PHY_INT                        ((u32)BIT(17))
+#define INT_ENP_MAC_ERR_INT            ((u32)BIT(15))
+#define INT_ENP_RX_FIFO_DATA_INT       ((u32)BIT(12))
+
+#endif /* _SMSC75XX_H */
index df9179a..d222d7e 100644 (file)
@@ -709,6 +709,8 @@ static void smsc95xx_start_rx_path(struct usbnet *dev)
 
 static int smsc95xx_phy_initialize(struct usbnet *dev)
 {
+       int bmcr, timeout = 0;
+
        /* Initialize MII structure */
        dev->mii.dev = dev->net;
        dev->mii.mdio_read = smsc95xx_mdio_read;
@@ -717,7 +719,20 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
        dev->mii.reg_num_mask = 0x1f;
        dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID;
 
+       /* reset phy and wait for reset to complete */
        smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+
+       do {
+               msleep(10);
+               bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
+               timeout++;
+       } while ((bmcr & MII_BMCR) && (timeout < 100));
+
+       if (timeout >= 100) {
+               netdev_warn(dev->net, "timeout on PHY Reset");
+               return -EIO;
+       }
+
        smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
                ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
                ADVERTISE_PAUSE_ASYM);
index 3d102dd..0b51857 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_PPC) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 obj-$(CONFIG_MN10300) += setup-bus.o
+obj-$(CONFIG_MICROBLAZE) += setup-bus.o
 
 #
 # ACPI Related PCI FW Functions
index a04f21c..f5da626 100644 (file)
@@ -133,6 +133,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
                sockets[i].socket.map_size = 0x1000;
                sockets[i].socket.irq_mask = 0;
                sockets[i].socket.pci_irq  = dev->irq;
+               sockets[i].socket.cb_dev  = dev;
                sockets[i].socket.owner = THIS_MODULE;
 
                sockets[i].number = i;
index 849ef1b..3f84d7a 100644 (file)
@@ -95,6 +95,7 @@
 #define I365_CSC_DETECT        0x08
 #define I365_CSC_ANY   0x0F
 #define I365_CSC_GPI   0x10
+#define I365_CSC_IRQ_MASK      0xF0
 
 /* Flags for I365_ADDRWIN */
 #define I365_ENA_IO(map)       (0x40 << (map))
index b2df041..c4612c5 100644 (file)
@@ -256,6 +256,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
 {
        struct pcmcia_socket *s;
        config_t *c;
+       int ret;
 
        s = p_dev->socket;
 
@@ -264,13 +265,13 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
 
        if (!(s->state & SOCKET_PRESENT)) {
                dev_dbg(&s->dev, "No card present\n");
-               mutex_unlock(&s->ops_mutex);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto unlock;
        }
        if (!(c->state & CONFIG_LOCKED)) {
                dev_dbg(&s->dev, "Configuration isnt't locked\n");
-               mutex_unlock(&s->ops_mutex);
-               return -EACCES;
+               ret = -EACCES;
+               goto unlock;
        }
 
        if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
@@ -286,7 +287,8 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
 
        if (mod->Attributes & CONF_VCC_CHANGE_VALID) {
                dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        /* We only allow changing Vpp1 and Vpp2 to the same value */
@@ -294,21 +296,21 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
            (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
                if (mod->Vpp1 != mod->Vpp2) {
                        dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n");
-                       mutex_unlock(&s->ops_mutex);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto unlock;
                }
                s->socket.Vpp = mod->Vpp1;
                if (s->ops->set_socket(s, &s->socket)) {
-                       mutex_unlock(&s->ops_mutex);
                        dev_printk(KERN_WARNING, &s->dev,
                                   "Unable to set VPP\n");
-                       return -EIO;
+                       ret = -EIO;
+                       goto unlock;
                }
        } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
                   (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
                dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
-               mutex_unlock(&s->ops_mutex);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
@@ -332,9 +334,11 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
                        s->ops->set_io_map(s, &io_on);
                }
        }
+       ret = 0;
+unlock:
        mutex_unlock(&s->ops_mutex);
 
-       return 0;
+       return ret;
 } /* modify_configuration */
 EXPORT_SYMBOL(pcmcia_modify_configuration);
 
@@ -752,14 +756,6 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 
 #ifdef CONFIG_PCMCIA_PROBE
 
-#ifdef IRQ_NOAUTOEN
-       /* if the underlying IRQ infrastructure allows for it, only allocate
-        * the IRQ, but do not enable it
-        */
-       if (!(req->Handler))
-               type |= IRQ_NOAUTOEN;
-#endif /* IRQ_NOAUTOEN */
-
        if (s->irq.AssignedIRQ != 0) {
                /* If the interrupt is already assigned, it must be the same */
                irq = s->irq.AssignedIRQ;
index 7c20491..7ba57a5 100644 (file)
@@ -671,6 +671,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
                socket[i].socket.map_size = 0x1000;
                socket[i].socket.irq_mask = mask;
                socket[i].socket.pci_irq  = dev->irq;
+               socket[i].socket.cb_dev = dev;
                socket[i].socket.owner = THIS_MODULE;
 
                socket[i].number = i;
index aaa7022..9ffa97d 100644 (file)
@@ -296,7 +296,7 @@ static int ti_init(struct yenta_socket *socket)
        u8 new, reg = exca_readb(socket, I365_INTCTL);
 
        new = reg & ~I365_INTR_ENA;
-       if (socket->cb_irq)
+       if (socket->dev->irq)
                new |= I365_INTR_ENA;
        if (new != reg)
                exca_writeb(socket, I365_INTCTL, new);
@@ -316,14 +316,47 @@ static int ti_override(struct yenta_socket *socket)
        return 0;
 }
 
+static void ti113x_use_isa_irq(struct yenta_socket *socket)
+{
+       int isa_irq = -1;
+       u8 intctl;
+       u32 isa_irq_mask = 0;
+
+       if (!isa_probe)
+               return;
+
+       /* get a free isa int */
+       isa_irq_mask = yenta_probe_irq(socket, isa_interrupts);
+       if (!isa_irq_mask)
+               return; /* no useable isa irq found */
+
+       /* choose highest available */
+       for (; isa_irq_mask; isa_irq++)
+               isa_irq_mask >>= 1;
+       socket->cb_irq = isa_irq;
+
+       exca_writeb(socket, I365_CSCINT, (isa_irq << 4));
+
+       intctl = exca_readb(socket, I365_INTCTL);
+       intctl &= ~(I365_INTR_ENA | I365_IRQ_MASK);     /* CSC Enable */
+       exca_writeb(socket, I365_INTCTL, intctl);
+
+       dev_info(&socket->dev->dev,
+               "Yenta TI113x: using isa irq %d for CardBus\n", isa_irq);
+}
+
+
 static int ti113x_override(struct yenta_socket *socket)
 {
        u8 cardctl;
 
        cardctl = config_readb(socket, TI113X_CARD_CONTROL);
        cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
-       if (socket->cb_irq)
+       if (socket->dev->irq)
                cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
+       else
+               ti113x_use_isa_irq(socket);
+
        config_writeb(socket, TI113X_CARD_CONTROL, cardctl);
 
        return ti_override(socket);
index c9fcbdc..aaccdb9 100644 (file)
@@ -105,6 +105,7 @@ typedef struct vrc4171_socket {
        char name[24];
        int csc_irq;
        int io_irq;
+       spinlock_t lock;
 } vrc4171_socket_t;
 
 static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS];
@@ -327,7 +328,7 @@ static int pccard_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
        slot = sock->sock;
        socket = &vrc4171_sockets[slot];
 
-       spin_lock_irq(&sock->lock);
+       spin_lock_irq(&socket->lock);
 
        voltage = set_Vcc_value(state->Vcc);
        exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage);
@@ -370,7 +371,7 @@ static int pccard_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
                cscint |= I365_CSC_DETECT;
         exca_write_byte(slot, I365_CSCINT, cscint);
 
-       spin_unlock_irq(&sock->lock);
+       spin_unlock_irq(&socket->lock);
 
        return 0;
 }
index 967c766..418988a 100644 (file)
@@ -42,6 +42,18 @@ module_param_string(o2_speedup, o2_speedup, sizeof(o2_speedup), 0444);
 MODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
        "or 'default' (uses recommended behaviour for the detected bridge)");
 
+/*
+ * Only probe "regular" interrupts, don't
+ * touch dangerous spots like the mouse irq,
+ * because there are mice that apparently
+ * get really confused if they get fondled
+ * too intimately.
+ *
+ * Default to 11, 10, 9, 7, 6, 5, 4, 3.
+ */
+static u32 isa_interrupts = 0x0ef8;
+
+
 #define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
 
 /* Don't ask.. */
@@ -54,6 +66,8 @@ MODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
  */
 #ifdef CONFIG_YENTA_TI
 static int yenta_probe_cb_irq(struct yenta_socket *socket);
+static unsigned int yenta_probe_irq(struct yenta_socket *socket,
+                               u32 isa_irq_mask);
 #endif
 
 
@@ -329,8 +343,8 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
                /* ISA interrupt control? */
                intr = exca_readb(socket, I365_INTCTL);
                intr = (intr & ~0xf);
-               if (!socket->cb_irq) {
-                       intr |= state->io_irq;
+               if (!socket->dev->irq) {
+                       intr |= socket->cb_irq ? socket->cb_irq : state->io_irq;
                        bridge |= CB_BRIDGE_INTR;
                }
                exca_writeb(socket, I365_INTCTL, intr);
@@ -340,7 +354,7 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
                reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
                reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
                reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
-               if (state->io_irq != socket->cb_irq) {
+               if (state->io_irq != socket->dev->irq) {
                        reg |= state->io_irq;
                        bridge |= CB_BRIDGE_INTR;
                }
@@ -356,7 +370,9 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
                        exca_writeb(socket, I365_POWER, reg);
 
                /* CSC interrupt: no ISA irq for CSC */
-               reg = I365_CSC_DETECT;
+               reg = exca_readb(socket, I365_CSCINT);
+               reg &= I365_CSC_IRQ_MASK;
+               reg |= I365_CSC_DETECT;
                if (state->flags & SS_IOCARD) {
                        if (state->csc_mask & SS_STSCHG)
                                reg |= I365_CSC_STSCHG;
@@ -896,22 +912,12 @@ static struct cardbus_type cardbus_type[] = {
 };
 
 
-/*
- * Only probe "regular" interrupts, don't
- * touch dangerous spots like the mouse irq,
- * because there are mice that apparently
- * get really confused if they get fondled
- * too intimately.
- *
- * Default to 11, 10, 9, 7, 6, 5, 4, 3.
- */
-static u32 isa_interrupts = 0x0ef8;
-
 static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask)
 {
        int i;
        unsigned long val;
        u32 mask;
+       u8 reg;
 
        /*
         * Probe for usable interrupts using the force
@@ -919,6 +925,7 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas
         */
        cb_writel(socket, CB_SOCKET_EVENT, -1);
        cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+       reg = exca_readb(socket, I365_CSCINT);
        exca_writeb(socket, I365_CSCINT, 0);
        val = probe_irq_on() & isa_irq_mask;
        for (i = 1; i < 16; i++) {
@@ -930,7 +937,7 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas
                cb_writel(socket, CB_SOCKET_EVENT, -1);
        }
        cb_writel(socket, CB_SOCKET_MASK, 0);
-       exca_writeb(socket, I365_CSCINT, 0);
+       exca_writeb(socket, I365_CSCINT, reg);
 
        mask = probe_irq_mask(val) & 0xffff;
 
@@ -967,6 +974,8 @@ static irqreturn_t yenta_probe_handler(int irq, void *dev_id)
 /* probes the PCI interrupt, use only on override functions */
 static int yenta_probe_cb_irq(struct yenta_socket *socket)
 {
+       u8 reg;
+
        if (!socket->cb_irq)
                return -1;
 
@@ -979,7 +988,8 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
        }
 
        /* generate interrupt, wait */
-       exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG);
+       reg = exca_readb(socket, I365_CSCINT);
+       exca_writeb(socket, I365_CSCINT, reg | I365_CSC_STSCHG);
        cb_writel(socket, CB_SOCKET_EVENT, -1);
        cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
        cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
@@ -988,7 +998,7 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
 
        /* disable interrupts */
        cb_writel(socket, CB_SOCKET_MASK, 0);
-       exca_writeb(socket, I365_CSCINT, 0);
+       exca_writeb(socket, I365_CSCINT, reg);
        cb_writel(socket, CB_SOCKET_EVENT, -1);
        exca_readb(socket, I365_CSC);
 
index 226b3e9..cbca40a 100644 (file)
@@ -922,9 +922,13 @@ static struct backlight_ops acer_bl_ops = {
 
 static int __devinit acer_backlight_init(struct device *dev)
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
 
-       bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = max_brightness;
+       bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
+                                      &props);
        if (IS_ERR(bd)) {
                printk(ACER_ERR "Could not register Acer backlight device\n");
                acer_backlight_device = NULL;
@@ -935,7 +939,6 @@ static int __devinit acer_backlight_init(struct device *dev)
 
        bd->props.power = FB_BLANK_UNBLANK;
        bd->props.brightness = read_brightness(bd);
-       bd->props.max_brightness = max_brightness;
        backlight_update_status(bd);
        return 0;
 }
index 791fcf3..db5f7db 100644 (file)
@@ -639,12 +639,16 @@ static int asus_backlight_init(struct asus_laptop *asus)
 {
        struct backlight_device *bd;
        struct device *dev = &asus->platform_device->dev;
+       struct backlight_properties props;
 
        if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
            !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
            lcd_switch_handle) {
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = 15;
+
                bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
-                                              asus, &asusbl_ops);
+                                              asus, &asusbl_ops, &props);
                if (IS_ERR(bd)) {
                        pr_err("Could not register asus backlight device\n");
                        asus->backlight_device = NULL;
@@ -653,7 +657,6 @@ static int asus_backlight_init(struct asus_laptop *asus)
 
                asus->backlight_device = bd;
 
-               bd->props.max_brightness = 15;
                bd->props.power = FB_BLANK_UNBLANK;
                bd->props.brightness = asus_read_brightness(bd);
                backlight_update_status(bd);
index 1381430..ee52035 100644 (file)
@@ -1481,6 +1481,7 @@ static void asus_acpi_exit(void)
 
 static int __init asus_acpi_init(void)
 {
+       struct backlight_properties props;
        int result;
 
        result = acpi_bus_register_driver(&asus_hotk_driver);
@@ -1507,15 +1508,17 @@ static int __init asus_acpi_init(void)
                return -ENODEV;
        }
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 15;
        asus_backlight_device = backlight_device_register("asus", NULL, NULL,
-                                                         &asus_backlight_data);
+                                                         &asus_backlight_data,
+                                                         &props);
        if (IS_ERR(asus_backlight_device)) {
                printk(KERN_ERR "Could not register asus backlight device\n");
                asus_backlight_device = NULL;
                asus_acpi_exit();
                return -ENODEV;
        }
-       asus_backlight_device->props.max_brightness = 15;
 
        return 0;
 }
index 035a7dd..c696cf1 100644 (file)
@@ -455,18 +455,22 @@ static int cmpc_bl_update_status(struct backlight_device *bd)
                return -1;
 }
 
-static struct backlight_ops cmpc_bl_ops = {
+static const struct backlight_ops cmpc_bl_ops = {
        .get_brightness = cmpc_bl_get_brightness,
        .update_status = cmpc_bl_update_status
 };
 
 static int cmpc_bl_add(struct acpi_device *acpi)
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
 
-       bd = backlight_device_register("cmpc_bl", &acpi->dev,
-                                      acpi->handle, &cmpc_bl_ops);
-       bd->props.max_brightness = 7;
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 7;
+       bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle,
+                                      &cmpc_bl_ops, &props);
+       if (IS_ERR(bd))
+               return PTR_ERR(bd);
        dev_set_drvdata(&acpi->dev, bd);
        return 0;
 }
index 2740b40..71ff154 100644 (file)
@@ -291,12 +291,15 @@ static int __init compal_init(void)
        /* Register backlight stuff */
 
        if (!acpi_video_backlight_support()) {
-               compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
-                                                           &compalbl_ops);
+               struct backlight_properties props;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = COMPAL_LCD_LEVEL_MAX - 1;
+               compalbl_device = backlight_device_register("compal-laptop",
+                                                           NULL, NULL,
+                                                           &compalbl_ops,
+                                                           &props);
                if (IS_ERR(compalbl_device))
                        return PTR_ERR(compalbl_device);
-
-               compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
        }
 
        ret = platform_driver_register(&compal_driver);
index ef61497..46435ac 100644 (file)
@@ -559,10 +559,14 @@ static int __init dell_init(void)
        release_buffer();
 
        if (max_intensity) {
-               dell_backlight_device = backlight_device_register(
-                       "dell_backlight",
-                       &platform_device->dev, NULL,
-                       &dell_ops);
+               struct backlight_properties props;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = max_intensity;
+               dell_backlight_device = backlight_device_register("dell_backlight",
+                                                                 &platform_device->dev,
+                                                                 NULL,
+                                                                 &dell_ops,
+                                                                 &props);
 
                if (IS_ERR(dell_backlight_device)) {
                        ret = PTR_ERR(dell_backlight_device);
@@ -570,7 +574,6 @@ static int __init dell_init(void)
                        goto fail_backlight;
                }
 
-               dell_backlight_device->props.max_brightness = max_intensity;
                dell_backlight_device->props.brightness =
                        dell_get_intensity(dell_backlight_device);
                backlight_update_status(dell_backlight_device);
index 9a844ca..3fdf21e 100644 (file)
@@ -1131,18 +1131,20 @@ static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
 
 static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 15;
        bd = backlight_device_register(EEEPC_LAPTOP_FILE,
-                                      &eeepc->platform_device->dev,
-                                      eeepc, &eeepcbl_ops);
+                                      &eeepc->platform_device->dev, eeepc,
+                                      &eeepcbl_ops, &props);
        if (IS_ERR(bd)) {
                pr_err("Could not register eeepc backlight device\n");
                eeepc->backlight_device = NULL;
                return PTR_ERR(bd);
        }
        eeepc->backlight_device = bd;
-       bd->props.max_brightness = 15;
        bd->props.brightness = read_brightness(bd);
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index 5f3320d..c1074b3 100644 (file)
@@ -1126,16 +1126,20 @@ static int __init fujitsu_init(void)
        /* Register backlight stuff */
 
        if (!acpi_video_backlight_support()) {
-               fujitsu->bl_device =
-                       backlight_device_register("fujitsu-laptop", NULL, NULL,
-                                                 &fujitsubl_ops);
+               struct backlight_properties props;
+
+               memset(&props, 0, sizeof(struct backlight_properties));
+               max_brightness = fujitsu->max_brightness;
+               props.max_brightness = max_brightness - 1;
+               fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
+                                                              NULL, NULL,
+                                                              &fujitsubl_ops,
+                                                              &props);
                if (IS_ERR(fujitsu->bl_device)) {
                        ret = PTR_ERR(fujitsu->bl_device);
                        fujitsu->bl_device = NULL;
                        goto fail_sysfs_group;
                }
-               max_brightness = fujitsu->max_brightness;
-               fujitsu->bl_device->props.max_brightness = max_brightness - 1;
                fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
        }
 
index c2b05da..996223a 100644 (file)
@@ -683,11 +683,14 @@ static int __init msi_init(void)
                printk(KERN_INFO "MSI: Brightness ignored, must be controlled "
                       "by ACPI video driver\n");
        } else {
+               struct backlight_properties props;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
                msibl_device = backlight_device_register("msi-laptop-bl", NULL,
-                                                        NULL, &msibl_ops);
+                                                        NULL, &msibl_ops,
+                                                        &props);
                if (IS_ERR(msibl_device))
                        return PTR_ERR(msibl_device);
-               msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
        }
 
        ret = platform_driver_register(&msipf_driver);
index f5f70d4..367caaa 100644 (file)
@@ -138,7 +138,7 @@ static int bl_set_status(struct backlight_device *bd)
        return msi_wmi_set_block(0, backlight_map[bright]);
 }
 
-static struct backlight_ops msi_backlight_ops = {
+static const struct backlight_ops msi_backlight_ops = {
        .get_brightness = bl_get,
        .update_status  = bl_set_status,
 };
@@ -249,12 +249,17 @@ static int __init msi_wmi_init(void)
                goto err_uninstall_notifier;
 
        if (!acpi_video_backlight_support()) {
-               backlight = backlight_device_register(DRV_NAME,
-                               NULL, NULL, &msi_backlight_ops);
-               if (IS_ERR(backlight))
+               struct backlight_properties props;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
+               backlight = backlight_device_register(DRV_NAME, NULL, NULL,
+                                                     &msi_backlight_ops,
+                                                     &props);
+               if (IS_ERR(backlight)) {
+                       err = PTR_ERR(backlight);
                        goto err_free_input;
+               }
 
-               backlight->props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
                err = bl_get(NULL);
                if (err < 0)
                        goto err_free_backlight;
index c9fc479..726f02a 100644 (file)
@@ -352,7 +352,7 @@ static int bl_set_status(struct backlight_device *bd)
        return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
 }
 
-static struct backlight_ops pcc_backlight_ops = {
+static const struct backlight_ops pcc_backlight_ops = {
        .get_brightness = bl_get,
        .update_status  = bl_set_status,
 };
@@ -600,6 +600,7 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device)
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device)
 {
+       struct backlight_properties props;
        struct pcc_acpi *pcc;
        int num_sifr, result;
 
@@ -637,24 +638,25 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
        if (result) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                  "Error installing keyinput handler\n"));
-               goto out_sinf;
+               goto out_hotkey;
        }
 
-       /* initialize backlight */
-       pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
-                                                  &pcc_backlight_ops);
-       if (IS_ERR(pcc->backlight))
-               goto out_input;
-
        if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                 "Couldn't retrieve BIOS data\n"));
-               goto out_backlight;
+               goto out_input;
+       }
+       /* initialize backlight */
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
+       pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
+                                                  &pcc_backlight_ops, &props);
+       if (IS_ERR(pcc->backlight)) {
+               result = PTR_ERR(pcc->backlight);
+               goto out_sinf;
        }
 
        /* read the initial brightness setting from the hardware */
-       pcc->backlight->props.max_brightness =
-                                       pcc->sinf[SINF_AC_MAX_BRIGHT];
        pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
 
        /* read the initial sticky key mode from the hardware */
@@ -669,12 +671,12 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
 
 out_backlight:
        backlight_device_unregister(pcc->backlight);
+out_sinf:
+       kfree(pcc->sinf);
 out_input:
        input_unregister_device(pcc->input_dev);
        /* no need to input_free_device() since core input API refcount and
         * free()s the device */
-out_sinf:
-       kfree(pcc->sinf);
 out_hotkey:
        kfree(pcc);
 
index 5a3d851..6553b91 100644 (file)
@@ -1291,9 +1291,13 @@ static int sony_nc_add(struct acpi_device *device)
                       "controlled by ACPI video driver\n");
        } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
                                                &handle))) {
+                                                       struct backlight_properties props;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
                sony_backlight_device = backlight_device_register("sony", NULL,
                                                                  NULL,
-                                                                 &sony_backlight_ops);
+                                                                 &sony_backlight_ops,
+                                                                 &props);
 
                if (IS_ERR(sony_backlight_device)) {
                        printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
@@ -1302,8 +1306,6 @@ static int sony_nc_add(struct acpi_device *device)
                        sony_backlight_device->props.brightness =
                            sony_backlight_get_brightness
                            (sony_backlight_device);
-                       sony_backlight_device->props.max_brightness =
-                           SONY_MAX_BRIGHTNESS - 1;
                }
 
        }
index c64e352..770b853 100644 (file)
@@ -6170,6 +6170,7 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
 
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
+       struct backlight_properties props;
        int b;
        unsigned long quirks;
 
@@ -6259,9 +6260,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                printk(TPACPI_INFO
                       "detected a 16-level brightness capable ThinkPad\n");
 
-       ibm_backlight_device = backlight_device_register(
-                                       TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
-                                       &ibm_backlight_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = (tp_features.bright_16levels) ? 15 : 7;
+       ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
+                                                        NULL, NULL,
+                                                        &ibm_backlight_data,
+                                                        &props);
        if (IS_ERR(ibm_backlight_device)) {
                int rc = PTR_ERR(ibm_backlight_device);
                ibm_backlight_device = NULL;
@@ -6280,8 +6284,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                        "or not on your ThinkPad\n", TPACPI_MAIL);
        }
 
-       ibm_backlight_device->props.max_brightness =
-                               (tp_features.bright_16levels)? 15 : 7;
        ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
        backlight_update_status(ibm_backlight_device);
 
index 789240d..def4841 100644 (file)
@@ -924,6 +924,7 @@ static int __init toshiba_acpi_init(void)
        u32 hci_result;
        bool bt_present;
        int ret = 0;
+       struct backlight_properties props;
 
        if (acpi_disabled)
                return -ENODEV;
@@ -974,10 +975,12 @@ static int __init toshiba_acpi_init(void)
                }
        }
 
+       props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
        toshiba_backlight_device = backlight_device_register("toshiba",
-                                               &toshiba_acpi.p_dev->dev,
-                                               NULL,
-                                               &toshiba_backlight_data);
+                                                            &toshiba_acpi.p_dev->dev,
+                                                            NULL,
+                                                            &toshiba_backlight_data,
+                                                            &props);
         if (IS_ERR(toshiba_backlight_device)) {
                ret = PTR_ERR(toshiba_backlight_device);
 
@@ -986,7 +989,6 @@ static int __init toshiba_acpi_init(void)
                toshiba_acpi_exit();
                return ret;
        }
-        toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
 
        /* Register rfkill switch for Bluetooth */
        if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
index b3beab6..fc7ae05 100644 (file)
@@ -704,6 +704,13 @@ int sclp_chp_deconfigure(struct chp_id chpid)
        return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
 }
 
+int arch_get_memory_phys_device(unsigned long start_pfn)
+{
+       if (!rzm)
+               return 0;
+       return PFN_PHYS(start_pfn) / rzm;
+}
+
 struct chp_info_sccb {
        struct sccb_header header;
        u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
index 9191d1e..75f2336 100644 (file)
@@ -1,9 +1,15 @@
 menu "SCSI device support"
 
+config SCSI_MOD
+       tristate
+       default y if SCSI=n || SCSI=y
+       default m if SCSI=m
+
 config RAID_ATTRS
        tristate "RAID Transport Class"
        default n
        depends on BLOCK
+       depends on SCSI_MOD
        ---help---
          Provides RAID
 
index 6709857..cda6642 100644 (file)
@@ -32,18 +32,11 @@ void be_mcc_notify(struct beiscsi_hba *phba)
 unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
 {
        unsigned int tag = 0;
-       unsigned int num = 0;
 
-mcc_tag_rdy:
        if (phba->ctrl.mcc_tag_available) {
                tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
                phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
                phba->ctrl.mcc_numtag[tag] = 0;
-       } else {
-               udelay(100);
-               num++;
-               if (num < mcc_timeout)
-                       goto mcc_tag_rdy;
        }
        if (tag) {
                phba->ctrl.mcc_tag_available--;
index 29a3aaf..c3928cb 100644 (file)
@@ -482,7 +482,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
        tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep);
        if (!tag) {
                SE_DEBUG(DBG_LVL_1,
-                        "mgmt_invalidate_connection Failed for cid=%d \n",
+                        "mgmt_open_connection Failed for cid=%d \n",
                         beiscsi_ep->ep_cid);
        } else {
                wait_event_interruptible(phba->ctrl.mcc_wait[tag],
@@ -701,7 +701,7 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
        if (!tag) {
                SE_DEBUG(DBG_LVL_1,
                         "mgmt_invalidate_connection Failed for cid=%d \n",
-                        beiscsi_ep->ep_cid);
+                         beiscsi_ep->ep_cid);
        } else {
                wait_event_interruptible(phba->ctrl.mcc_wait[tag],
                                         phba->ctrl.mcc_numtag[tag]);
index 7c22616..fcfb29e 100644 (file)
@@ -58,6 +58,123 @@ static int beiscsi_slave_configure(struct scsi_device *sdev)
        return 0;
 }
 
+static int beiscsi_eh_abort(struct scsi_cmnd *sc)
+{
+       struct iscsi_cls_session *cls_session;
+       struct iscsi_task *aborted_task = (struct iscsi_task *)sc->SCp.ptr;
+       struct beiscsi_io_task *aborted_io_task;
+       struct iscsi_conn *conn;
+       struct beiscsi_conn *beiscsi_conn;
+       struct beiscsi_hba *phba;
+       struct iscsi_session *session;
+       struct invalidate_command_table *inv_tbl;
+       unsigned int cid, tag, num_invalidate;
+
+       cls_session = starget_to_session(scsi_target(sc->device));
+       session = cls_session->dd_data;
+
+       spin_lock_bh(&session->lock);
+       if (!aborted_task || !aborted_task->sc) {
+               /* we raced */
+               spin_unlock_bh(&session->lock);
+               return SUCCESS;
+       }
+
+       aborted_io_task = aborted_task->dd_data;
+       if (!aborted_io_task->scsi_cmnd) {
+               /* raced or invalid command */
+               spin_unlock_bh(&session->lock);
+               return SUCCESS;
+       }
+       spin_unlock_bh(&session->lock);
+       conn = aborted_task->conn;
+       beiscsi_conn = conn->dd_data;
+       phba = beiscsi_conn->phba;
+
+       /* invalidate iocb */
+       cid = beiscsi_conn->beiscsi_conn_cid;
+       inv_tbl = phba->inv_tbl;
+       memset(inv_tbl, 0x0, sizeof(*inv_tbl));
+       inv_tbl->cid = cid;
+       inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index;
+       num_invalidate = 1;
+       tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+       if (!tag) {
+               shost_printk(KERN_WARNING, phba->shost,
+                            "mgmt_invalidate_icds could not be"
+                            " submitted\n");
+               return FAILED;
+       } else {
+               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+                                        phba->ctrl.mcc_numtag[tag]);
+               free_mcc_tag(&phba->ctrl, tag);
+       }
+
+       return iscsi_eh_abort(sc);
+}
+
+static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
+{
+       struct iscsi_task *abrt_task;
+       struct beiscsi_io_task *abrt_io_task;
+       struct iscsi_conn *conn;
+       struct beiscsi_conn *beiscsi_conn;
+       struct beiscsi_hba *phba;
+       struct iscsi_session *session;
+       struct iscsi_cls_session *cls_session;
+       struct invalidate_command_table *inv_tbl;
+       unsigned int cid, tag, i, num_invalidate;
+       int rc = FAILED;
+
+       /* invalidate iocbs */
+       cls_session = starget_to_session(scsi_target(sc->device));
+       session = cls_session->dd_data;
+       spin_lock_bh(&session->lock);
+       if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+               goto unlock;
+
+       conn = session->leadconn;
+       beiscsi_conn = conn->dd_data;
+       phba = beiscsi_conn->phba;
+       cid = beiscsi_conn->beiscsi_conn_cid;
+       inv_tbl = phba->inv_tbl;
+       memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN);
+       num_invalidate = 0;
+       for (i = 0; i < conn->session->cmds_max; i++) {
+               abrt_task = conn->session->cmds[i];
+               abrt_io_task = abrt_task->dd_data;
+               if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
+                       continue;
+
+               if (abrt_task->sc->device->lun != abrt_task->sc->device->lun)
+                       continue;
+
+               inv_tbl->cid = cid;
+               inv_tbl->icd = abrt_io_task->psgl_handle->sgl_index;
+               num_invalidate++;
+               inv_tbl++;
+       }
+       spin_unlock_bh(&session->lock);
+       inv_tbl = phba->inv_tbl;
+
+       tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+       if (!tag) {
+               shost_printk(KERN_WARNING, phba->shost,
+                            "mgmt_invalidate_icds could not be"
+                            " submitted\n");
+               return FAILED;
+       } else {
+               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+                                        phba->ctrl.mcc_numtag[tag]);
+               free_mcc_tag(&phba->ctrl, tag);
+       }
+
+       return iscsi_eh_device_reset(sc);
+unlock:
+       spin_unlock_bh(&session->lock);
+       return rc;
+}
+
 /*------------------- PCI Driver operations and data ----------------- */
 static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
@@ -74,12 +191,12 @@ static struct scsi_host_template beiscsi_sht = {
        .name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
        .proc_name = DRV_NAME,
        .queuecommand = iscsi_queuecommand,
-       .eh_abort_handler = iscsi_eh_abort,
        .change_queue_depth = iscsi_change_queue_depth,
        .slave_configure = beiscsi_slave_configure,
        .target_alloc = iscsi_target_alloc,
-       .eh_device_reset_handler = iscsi_eh_device_reset,
-       .eh_target_reset_handler = iscsi_eh_target_reset,
+       .eh_abort_handler = beiscsi_eh_abort,
+       .eh_device_reset_handler = beiscsi_eh_device_reset,
+       .eh_target_reset_handler = iscsi_eh_session_reset,
        .sg_tablesize = BEISCSI_SGLIST_ELEMENTS,
        .can_queue = BE2_IO_DEPTH,
        .this_id = -1,
@@ -242,7 +359,7 @@ static void beiscsi_get_params(struct beiscsi_hba *phba)
                                    + BE2_TMFS
                                    + BE2_NOPOUT_REQ));
        phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count;
-       phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count;;
+       phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count * 2;
        phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;;
        phba->params.num_sge_per_io = BE2_SGE;
        phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
@@ -946,14 +1063,18 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
        case HWH_TYPE_IO:
        case HWH_TYPE_IO_RD:
                if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
-                   ISCSI_OP_NOOP_OUT) {
+                    ISCSI_OP_NOOP_OUT)
                        be_complete_nopin_resp(beiscsi_conn, task, psol);
-               else
+               else
                        be_complete_io(beiscsi_conn, task, psol);
                break;
 
        case HWH_TYPE_LOGOUT:
-               be_complete_logout(beiscsi_conn, task, psol);
+               if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
+                       be_complete_logout(beiscsi_conn, task, psol);
+               else
+                       be_complete_tmf(beiscsi_conn, task, psol);
+
                break;
 
        case HWH_TYPE_LOGIN:
@@ -962,10 +1083,6 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
                         "- Solicited path \n");
                break;
 
-       case HWH_TYPE_TMF:
-               be_complete_tmf(beiscsi_conn, task, psol);
-               break;
-
        case HWH_TYPE_NOP:
                be_complete_nopin_resp(beiscsi_conn, task, psol);
                break;
@@ -2052,7 +2169,7 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
        num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
                      ((sizeof(struct iscsi_wrb) *
                        phba->params.wrbs_per_cxn));
-       for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) {
+       for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
                pwrb_context = &phwi_ctrlr->wrb_context[index];
                if (num_cxn_wrb) {
                        for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
@@ -3073,14 +3190,18 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
                reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
                SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
                iowrite32(reg, addr);
-               for (i = 0; i <= phba->num_cpus; i++) {
-                       eq = &phwi_context->be_eq[i].q;
+               if (!phba->msix_enabled) {
+                       eq = &phwi_context->be_eq[0].q;
                        SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
                        hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+               } else {
+                       for (i = 0; i <= phba->num_cpus; i++) {
+                               eq = &phwi_context->be_eq[i].q;
+                               SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+                               hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+                       }
                }
-       } else
-               shost_printk(KERN_WARNING, phba->shost,
-                            "In hwi_enable_intr, Not Enabled \n");
+       }
        return true;
 }
 
@@ -3476,19 +3597,13 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
 
 static int beiscsi_mtask(struct iscsi_task *task)
 {
-       struct beiscsi_io_task *aborted_io_task, *io_task = task->dd_data;
+       struct beiscsi_io_task *io_task = task->dd_data;
        struct iscsi_conn *conn = task->conn;
        struct beiscsi_conn *beiscsi_conn = conn->dd_data;
        struct beiscsi_hba *phba = beiscsi_conn->phba;
-       struct iscsi_session *session;
        struct iscsi_wrb *pwrb = NULL;
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_wrb_context *pwrb_context;
-       struct wrb_handle *pwrb_handle;
        unsigned int doorbell = 0;
-       unsigned int i, cid;
-       struct iscsi_task *aborted_task;
-       unsigned int tag;
+       unsigned int cid;
 
        cid = beiscsi_conn->beiscsi_conn_cid;
        pwrb = io_task->pwrb_handle->pwrb;
@@ -3499,6 +3614,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
                      io_task->pwrb_handle->wrb_index);
        AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
                      io_task->psgl_handle->sgl_index);
+
        switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
        case ISCSI_OP_LOGIN:
                AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
@@ -3523,33 +3639,6 @@ static int beiscsi_mtask(struct iscsi_task *task)
                hwi_write_buffer(pwrb, task);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
-               session = conn->session;
-               i = ((struct iscsi_tm *)task->hdr)->rtt;
-               phwi_ctrlr = phba->phwi_ctrlr;
-               pwrb_context = &phwi_ctrlr->wrb_context[cid -
-                                           phba->fw_config.iscsi_cid_start];
-               pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i)
-                                                               >> 16];
-               aborted_task = pwrb_handle->pio_handle;
-                if (!aborted_task)
-                       return 0;
-
-               aborted_io_task = aborted_task->dd_data;
-               if (!aborted_io_task->scsi_cmnd)
-                       return 0;
-
-               tag = mgmt_invalidate_icds(phba,
-                                    aborted_io_task->psgl_handle->sgl_index,
-                                    cid);
-               if (!tag) {
-                       shost_printk(KERN_WARNING, phba->shost,
-                                    "mgmt_invalidate_icds could not be"
-                                    " submitted\n");
-               } else {
-                       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                                phba->ctrl.mcc_numtag[tag]);
-                       free_mcc_tag(&phba->ctrl, tag);
-               }
                AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
                              INI_TMF_CMD);
                AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
@@ -3558,7 +3647,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
        case ISCSI_OP_LOGOUT:
                AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
                AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                               HWH_TYPE_LOGOUT);
+                             HWH_TYPE_LOGOUT);
                hwi_write_buffer(pwrb, task);
                break;
 
@@ -3584,17 +3673,12 @@ static int beiscsi_mtask(struct iscsi_task *task)
 
 static int beiscsi_task_xmit(struct iscsi_task *task)
 {
-       struct iscsi_conn *conn = task->conn;
        struct beiscsi_io_task *io_task = task->dd_data;
        struct scsi_cmnd *sc = task->sc;
-       struct beiscsi_conn *beiscsi_conn = conn->dd_data;
        struct scatterlist *sg;
        int num_sg;
        unsigned int  writedir = 0, xferlen = 0;
 
-       SE_DEBUG(DBG_LVL_4, "\n cid=%d In beiscsi_task_xmit task=%p conn=%p \t"
-                "beiscsi_conn=%p \n", beiscsi_conn->beiscsi_conn_cid,
-                task, conn, beiscsi_conn);
        if (!sc)
                return beiscsi_mtask(task);
 
@@ -3699,7 +3783,6 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                        " Failed in beiscsi_hba_alloc \n");
                goto disable_pci;
        }
-       SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba);
 
        switch (pcidev->device) {
        case BE_DEVICE_ID1:
index c53a80a..87ec212 100644 (file)
@@ -257,6 +257,11 @@ struct hba_parameters {
        unsigned int num_sge;
 };
 
+struct invalidate_command_table {
+       unsigned short icd;
+       unsigned short cid;
+} __packed;
+
 struct beiscsi_hba {
        struct hba_parameters params;
        struct hwi_controller *phwi_ctrlr;
@@ -329,6 +334,8 @@ struct beiscsi_hba {
        struct work_struct work_cqs;    /* The work being queued */
        struct be_ctrl_info ctrl;
        unsigned int generation;
+       struct invalidate_command_table inv_tbl[128];
+
 };
 
 struct beiscsi_session {
@@ -491,8 +498,6 @@ struct hwi_async_entry {
        struct list_head data_busy_list;
 };
 
-#define BE_MIN_ASYNC_ENTRIES 128
-
 struct hwi_async_pdu_context {
        struct {
                struct be_bus_address pa_base;
@@ -533,7 +538,7 @@ struct hwi_async_pdu_context {
         * This is a varying size list! Do not add anything
         * after this entry!!
         */
-       struct hwi_async_entry async_entry[BE_MIN_ASYNC_ENTRIES];
+       struct hwi_async_entry async_entry[BE2_MAX_SESSIONS * 2];
 };
 
 #define PDUCQE_CODE_MASK       0x0000003F
index 317bcd0..72617b6 100644 (file)
@@ -145,14 +145,15 @@ unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
 }
 
 unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
-                                  unsigned int icd, unsigned int cid)
+                               struct invalidate_command_table *inv_tbl,
+                               unsigned int num_invalidate, unsigned int cid)
 {
        struct be_dma_mem nonemb_cmd;
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct be_mcc_wrb *wrb;
        struct be_sge *sge;
        struct invalidate_commands_params_in *req;
-       unsigned int tag = 0;
+       unsigned int i, tag = 0;
 
        spin_lock(&ctrl->mbox_lock);
        tag = alloc_mcc_tag(phba);
@@ -183,9 +184,12 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
                        sizeof(*req));
        req->ref_handle = 0;
        req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
-       req->icd_count = 0;
-       req->table[req->icd_count].icd = icd;
-       req->table[req->icd_count].cid = cid;
+       for (i = 0; i < num_invalidate; i++) {
+               req->table[i].icd = inv_tbl->icd;
+               req->table[i].cid = inv_tbl->cid;
+               req->icd_count++;
+               inv_tbl++;
+       }
        sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
        sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
        sge->len = cpu_to_le32(nonemb_cmd.size);
index ecead6a..3d316b8 100644 (file)
@@ -94,7 +94,8 @@ unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
                                     unsigned short cid,
                                     unsigned int upload_flag);
 unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
-                                  unsigned int icd, unsigned int cid);
+                               struct invalidate_command_table *inv_tbl,
+                               unsigned int num_invalidate, unsigned int cid);
 
 struct iscsi_invalidate_connection_params_in {
        struct be_cmd_req_hdr hdr;
@@ -116,11 +117,6 @@ union iscsi_invalidate_connection_params {
        struct iscsi_invalidate_connection_params_out response;
 } __packed;
 
-struct invalidate_command_table {
-       unsigned short icd;
-       unsigned short cid;
-} __packed;
-
 struct invalidate_commands_params_in {
        struct be_cmd_req_hdr hdr;
        unsigned int ref_handle;
index 1d60094..17e06ca 100644 (file)
@@ -2,14 +2,14 @@ obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
 
 bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o
 
-bfa-y += bfa_core.o bfa_ioc.o bfa_iocfc.o bfa_fcxp.o bfa_lps.o
-bfa-y += bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o 
+bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o
+bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o
 bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o
 bfa-y += bfa_itnim.o bfa_fcpim.o bfa_tskim.o bfa_log.o bfa_log_module.o
 bfa-y += bfa_csdebug.o bfa_sm.o plog.o
 
-bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o 
+bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o
 bfa-y += bfa_fcs_uf.o bfa_fcs_lport.o fab.o fdmi.o ms.o ns.o scn.o loop.o
 bfa-y += lport_api.o n2n.o rport.o rport_api.o rport_ftrs.o vport.o
 
-ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna
+ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna -DBFA_PERF_BUILD
index 44e2d11..0c08e18 100644 (file)
@@ -385,6 +385,15 @@ bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
 }
 
 /**
+ * Clear the saved firmware trace information of an IOC.
+ */
+void
+bfa_debug_fwsave_clear(struct bfa_s *bfa)
+{
+       bfa_ioc_debug_fwsave_clear(&bfa->ioc);
+}
+
+/**
  *             Fetch firmware trace data.
  *
  * @param[in]          bfa                     BFA instance
@@ -399,4 +408,14 @@ bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
 {
        return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
 }
+
+/**
+ * Reset hw semaphore & usage cnt regs and initialize.
+ */
+void
+bfa_chip_reset(struct bfa_s *bfa)
+{
+       bfa_ioc_ownership_reset(&bfa->ioc);
+       bfa_ioc_pll_init(&bfa->ioc);
+}
 #endif
index aef648b..c589488 100644 (file)
 #include <cs/bfa_plog.h>
 #include <aen/bfa_aen_port.h>
 
-BFA_TRC_FILE(HAL, PPORT);
-BFA_MODULE(pport);
-
-#define bfa_pport_callback(__pport, __event) do {                      \
-       if ((__pport)->bfa->fcs) {      \
-               (__pport)->event_cbfn((__pport)->event_cbarg, (__event));      \
-       } else {                                                        \
-               (__pport)->hcb_event = (__event);      \
-               bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe,        \
-               __bfa_cb_port_event, (__pport));      \
-       }                                                               \
-} while (0)
+BFA_TRC_FILE(HAL, FCPORT);
+BFA_MODULE(fcport);
 
 /*
  * The port is considered disabled if corresponding physical port or IOC are
  * disabled explicitly
  */
 #define BFA_PORT_IS_DISABLED(bfa) \
-       ((bfa_pport_is_disabled(bfa) == BFA_TRUE) || \
+       ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \
        (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
 
 /*
  * forward declarations
  */
-static bfa_boolean_t bfa_pport_send_enable(struct bfa_pport_s *port);
-static bfa_boolean_t bfa_pport_send_disable(struct bfa_pport_s *port);
-static void     bfa_pport_update_linkinfo(struct bfa_pport_s *pport);
-static void     bfa_pport_reset_linkinfo(struct bfa_pport_s *pport);
-static void     bfa_pport_set_wwns(struct bfa_pport_s *port);
-static void     __bfa_cb_port_event(void *cbarg, bfa_boolean_t complete);
-static void     __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete);
-static void     __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete);
-static void     bfa_port_stats_timeout(void *cbarg);
-static void     bfa_port_stats_clr_timeout(void *cbarg);
+static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport);
+static bfa_boolean_t bfa_fcport_send_disable(struct bfa_fcport_s *fcport);
+static void     bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport);
+static void     bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport);
+static void     bfa_fcport_set_wwns(struct bfa_fcport_s *fcport);
+static void     __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete);
+static void     bfa_fcport_callback(struct bfa_fcport_s *fcport,
+                               enum bfa_pport_linkstate event);
+static void     bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln,
+                               enum bfa_pport_linkstate event);
+static void     __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete);
+static void     bfa_fcport_stats_get_timeout(void *cbarg);
+static void     bfa_fcport_stats_clr_timeout(void *cbarg);
 
 /**
  *  bfa_pport_private
@@ -65,111 +58,114 @@ static void     bfa_port_stats_clr_timeout(void *cbarg);
 /**
  * BFA port state machine events
  */
-enum bfa_pport_sm_event {
-       BFA_PPORT_SM_START = 1, /*  start port state machine */
-       BFA_PPORT_SM_STOP = 2,  /*  stop port state machine */
-       BFA_PPORT_SM_ENABLE = 3,        /*  enable port */
-       BFA_PPORT_SM_DISABLE = 4,       /*  disable port state machine */
-       BFA_PPORT_SM_FWRSP = 5, /*  firmware enable/disable rsp */
-       BFA_PPORT_SM_LINKUP = 6,        /*  firmware linkup event */
-       BFA_PPORT_SM_LINKDOWN = 7,      /*  firmware linkup down */
-       BFA_PPORT_SM_QRESUME = 8,       /*  CQ space available */
-       BFA_PPORT_SM_HWFAIL = 9,        /*  IOC h/w failure */
+enum bfa_fcport_sm_event {
+       BFA_FCPORT_SM_START = 1,        /*  start port state machine */
+       BFA_FCPORT_SM_STOP = 2, /*  stop port state machine */
+       BFA_FCPORT_SM_ENABLE = 3,       /*  enable port */
+       BFA_FCPORT_SM_DISABLE = 4,      /*  disable port state machine */
+       BFA_FCPORT_SM_FWRSP = 5,        /*  firmware enable/disable rsp */
+       BFA_FCPORT_SM_LINKUP = 6,       /*  firmware linkup event */
+       BFA_FCPORT_SM_LINKDOWN = 7,     /*  firmware linkup down */
+       BFA_FCPORT_SM_QRESUME = 8,      /*  CQ space available */
+       BFA_FCPORT_SM_HWFAIL = 9,       /*  IOC h/w failure */
 };
 
-static void     bfa_pport_sm_uninit(struct bfa_pport_s *pport,
-                                   enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
-                                           enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_enabling(struct bfa_pport_s *pport,
-                                     enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_linkdown(struct bfa_pport_s *pport,
-                                     enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_linkup(struct bfa_pport_s *pport,
-                                   enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_disabling(struct bfa_pport_s *pport,
-                                      enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
-                                            enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_disabled(struct bfa_pport_s *pport,
-                                     enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_stopped(struct bfa_pport_s *pport,
-                                    enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
-                                    enum bfa_pport_sm_event event);
-static void     bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
-                                    enum bfa_pport_sm_event event);
+/**
+ * BFA port link notification state machine events
+ */
+
+enum bfa_fcport_ln_sm_event {
+       BFA_FCPORT_LN_SM_LINKUP         = 1,    /*  linkup event */
+       BFA_FCPORT_LN_SM_LINKDOWN       = 2,    /*  linkdown event */
+       BFA_FCPORT_LN_SM_NOTIFICATION   = 3     /*  done notification */
+};
+
+static void     bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
+                                       enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
+                                               enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
+                                        enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
+                                        enum bfa_fcport_sm_event event);
+static void     bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
+                                        enum bfa_fcport_sm_event event);
+
+static void     bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
+static void     bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln,
+                                        enum bfa_fcport_ln_sm_event event);
 
 static struct bfa_sm_table_s hal_pport_sm_table[] = {
-       {BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT},
-       {BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
-       {BFA_SM(bfa_pport_sm_enabling), BFA_PPORT_ST_ENABLING},
-       {BFA_SM(bfa_pport_sm_linkdown), BFA_PPORT_ST_LINKDOWN},
-       {BFA_SM(bfa_pport_sm_linkup), BFA_PPORT_ST_LINKUP},
-       {BFA_SM(bfa_pport_sm_disabling_qwait),
-        BFA_PPORT_ST_DISABLING_QWAIT},
-       {BFA_SM(bfa_pport_sm_disabling), BFA_PPORT_ST_DISABLING},
-       {BFA_SM(bfa_pport_sm_disabled), BFA_PPORT_ST_DISABLED},
-       {BFA_SM(bfa_pport_sm_stopped), BFA_PPORT_ST_STOPPED},
-       {BFA_SM(bfa_pport_sm_iocdown), BFA_PPORT_ST_IOCDOWN},
-       {BFA_SM(bfa_pport_sm_iocfail), BFA_PPORT_ST_IOCDOWN},
+       {BFA_SM(bfa_fcport_sm_uninit), BFA_PPORT_ST_UNINIT},
+       {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
+       {BFA_SM(bfa_fcport_sm_enabling), BFA_PPORT_ST_ENABLING},
+       {BFA_SM(bfa_fcport_sm_linkdown), BFA_PPORT_ST_LINKDOWN},
+       {BFA_SM(bfa_fcport_sm_linkup), BFA_PPORT_ST_LINKUP},
+       {BFA_SM(bfa_fcport_sm_disabling_qwait), BFA_PPORT_ST_DISABLING_QWAIT},
+       {BFA_SM(bfa_fcport_sm_disabling), BFA_PPORT_ST_DISABLING},
+       {BFA_SM(bfa_fcport_sm_disabled), BFA_PPORT_ST_DISABLED},
+       {BFA_SM(bfa_fcport_sm_stopped), BFA_PPORT_ST_STOPPED},
+       {BFA_SM(bfa_fcport_sm_iocdown), BFA_PPORT_ST_IOCDOWN},
+       {BFA_SM(bfa_fcport_sm_iocfail), BFA_PPORT_ST_IOCDOWN},
 };
 
 static void
-bfa_pport_aen_post(struct bfa_pport_s *pport, enum bfa_port_aen_event event)
+bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event)
 {
        union bfa_aen_data_u aen_data;
-       struct bfa_log_mod_s *logmod = pport->bfa->logm;
-       wwn_t           pwwn = pport->pwwn;
+       struct bfa_log_mod_s *logmod = fcport->bfa->logm;
+       wwn_t           pwwn = fcport->pwwn;
        char            pwwn_ptr[BFA_STRING_32];
-       struct bfa_ioc_attr_s ioc_attr;
 
+       memset(&aen_data, 0, sizeof(aen_data));
        wwn2str(pwwn_ptr, pwwn);
-       switch (event) {
-       case BFA_PORT_AEN_ONLINE:
-               bfa_log(logmod, BFA_AEN_PORT_ONLINE, pwwn_ptr);
-               break;
-       case BFA_PORT_AEN_OFFLINE:
-               bfa_log(logmod, BFA_AEN_PORT_OFFLINE, pwwn_ptr);
-               break;
-       case BFA_PORT_AEN_ENABLE:
-               bfa_log(logmod, BFA_AEN_PORT_ENABLE, pwwn_ptr);
-               break;
-       case BFA_PORT_AEN_DISABLE:
-               bfa_log(logmod, BFA_AEN_PORT_DISABLE, pwwn_ptr);
-               break;
-       case BFA_PORT_AEN_DISCONNECT:
-               bfa_log(logmod, BFA_AEN_PORT_DISCONNECT, pwwn_ptr);
-               break;
-       case BFA_PORT_AEN_QOS_NEG:
-               bfa_log(logmod, BFA_AEN_PORT_QOS_NEG, pwwn_ptr);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, event), pwwn_ptr);
 
-       bfa_ioc_get_attr(&pport->bfa->ioc, &ioc_attr);
-       aen_data.port.ioc_type = ioc_attr.ioc_type;
+       aen_data.port.ioc_type = bfa_get_type(fcport->bfa);
        aen_data.port.pwwn = pwwn;
 }
 
 static void
-bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_START:
+       case BFA_FCPORT_SM_START:
                /**
                 * Start event after IOC is configured and BFA is started.
                 */
-               if (bfa_pport_send_enable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+               if (bfa_fcport_send_enable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait);
                break;
 
-       case BFA_PPORT_SM_ENABLE:
+       case BFA_FCPORT_SM_ENABLE:
                /**
                 * Port is persistently configured to be in enabled state. Do
                 * not change state. Port enabling is done when START event is
@@ -177,389 +173,412 @@ bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
                 */
                break;
 
-       case BFA_PPORT_SM_DISABLE:
+       case BFA_FCPORT_SM_DISABLE:
                /**
                 * If a port is persistently configured to be disabled, the
                 * first event will a port disable request.
                 */
-               bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+               bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
-                           enum bfa_pport_sm_event event)
+bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
+                           enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_QRESUME:
-               bfa_sm_set_state(pport, bfa_pport_sm_enabling);
-               bfa_pport_send_enable(pport);
+       case BFA_FCPORT_SM_QRESUME:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
+               bfa_fcport_send_enable(fcport);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_reqq_wcancel(&pport->reqq_wait);
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+       case BFA_FCPORT_SM_STOP:
+               bfa_reqq_wcancel(&fcport->reqq_wait);
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                break;
 
-       case BFA_PPORT_SM_ENABLE:
+       case BFA_FCPORT_SM_ENABLE:
                /**
                 * Already enable is in progress.
                 */
                break;
 
-       case BFA_PPORT_SM_DISABLE:
+       case BFA_FCPORT_SM_DISABLE:
                /**
                 * Just send disable request to firmware when room becomes
                 * available in request queue.
                 */
-               bfa_sm_set_state(pport, bfa_pport_sm_disabled);
-               bfa_reqq_wcancel(&pport->reqq_wait);
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
+               bfa_reqq_wcancel(&fcport->reqq_wait);
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
-       case BFA_PPORT_SM_LINKUP:
-       case BFA_PPORT_SM_LINKDOWN:
+       case BFA_FCPORT_SM_LINKUP:
+       case BFA_FCPORT_SM_LINKDOWN:
                /**
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_reqq_wcancel(&pport->reqq_wait);
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_reqq_wcancel(&fcport->reqq_wait);
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_enabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
+               enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_FWRSP:
-       case BFA_PPORT_SM_LINKDOWN:
-               bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
+       case BFA_FCPORT_SM_FWRSP:
+       case BFA_FCPORT_SM_LINKDOWN:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown);
                break;
 
-       case BFA_PPORT_SM_LINKUP:
-               bfa_pport_update_linkinfo(pport);
-               bfa_sm_set_state(pport, bfa_pport_sm_linkup);
+       case BFA_FCPORT_SM_LINKUP:
+               bfa_fcport_update_linkinfo(fcport);
+               bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);
 
-               bfa_assert(pport->event_cbfn);
-               bfa_pport_callback(pport, BFA_PPORT_LINKUP);
+               bfa_assert(fcport->event_cbfn);
+               bfa_fcport_callback(fcport, BFA_PPORT_LINKUP);
                break;
 
-       case BFA_PPORT_SM_ENABLE:
+       case BFA_FCPORT_SM_ENABLE:
                /**
                 * Already being enabled.
                 */
                break;
 
-       case BFA_PPORT_SM_DISABLE:
-               if (bfa_pport_send_disable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+       case BFA_FCPORT_SM_DISABLE:
+               if (bfa_fcport_send_disable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait);
 
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_linkdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event;
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_LINKUP:
-               bfa_pport_update_linkinfo(pport);
-               bfa_sm_set_state(pport, bfa_pport_sm_linkup);
-               bfa_assert(pport->event_cbfn);
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+       case BFA_FCPORT_SM_LINKUP:
+               bfa_fcport_update_linkinfo(fcport);
+               bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);
+               bfa_assert(fcport->event_cbfn);
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
-               bfa_pport_callback(pport, BFA_PPORT_LINKUP);
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_ONLINE);
+
+               if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
+
+                       bfa_trc(fcport->bfa, pevent->link_state.fcf.fipenabled);
+                       bfa_trc(fcport->bfa, pevent->link_state.fcf.fipfailed);
+
+                       if (pevent->link_state.fcf.fipfailed)
+                               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
+                                       BFA_PL_EID_FIP_FCF_DISC, 0,
+                                       "FIP FCF Discovery Failed");
+                       else
+                               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
+                                       BFA_PL_EID_FIP_FCF_DISC, 0,
+                                       "FIP FCF Discovered");
+               }
+
+               bfa_fcport_callback(fcport, BFA_PPORT_LINKUP);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE);
                /**
                 * If QoS is enabled and it is not online,
                 * Send a separate event.
                 */
-               if ((pport->cfg.qos_enabled)
-                   && (bfa_os_ntohl(pport->qos_attr.state) != BFA_QOS_ONLINE))
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_QOS_NEG);
+               if ((fcport->cfg.qos_enabled)
+                   && (bfa_os_ntohl(fcport->qos_attr.state) != BFA_QOS_ONLINE))
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG);
 
                break;
 
-       case BFA_PPORT_SM_LINKDOWN:
+       case BFA_FCPORT_SM_LINKDOWN:
                /**
                 * Possible to get link down event.
                 */
                break;
 
-       case BFA_PPORT_SM_ENABLE:
+       case BFA_FCPORT_SM_ENABLE:
                /**
                 * Already enabled.
                 */
                break;
 
-       case BFA_PPORT_SM_DISABLE:
-               if (bfa_pport_send_disable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+       case BFA_FCPORT_SM_DISABLE:
+               if (bfa_fcport_send_disable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait);
 
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_ENABLE:
+       case BFA_FCPORT_SM_ENABLE:
                /**
                 * Already enabled.
                 */
                break;
 
-       case BFA_PPORT_SM_DISABLE:
-               if (bfa_pport_send_disable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+       case BFA_FCPORT_SM_DISABLE:
+               if (bfa_fcport_send_disable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait);
 
-               bfa_pport_reset_linkinfo(pport);
-               bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_fcport_reset_linkinfo(fcport);
+               bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN);
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
-       case BFA_PPORT_SM_LINKDOWN:
-               bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
-               bfa_pport_reset_linkinfo(pport);
-               bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+       case BFA_FCPORT_SM_LINKDOWN:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown);
+               bfa_fcport_reset_linkinfo(fcport);
+               bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN);
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
-               if (BFA_PORT_IS_DISABLED(pport->bfa))
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
                else
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
-               bfa_pport_reset_linkinfo(pport);
-               if (BFA_PORT_IS_DISABLED(pport->bfa))
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
+               bfa_fcport_reset_linkinfo(fcport);
+               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
                else
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
-               bfa_pport_reset_linkinfo(pport);
-               bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
-               if (BFA_PORT_IS_DISABLED(pport->bfa))
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
+               bfa_fcport_reset_linkinfo(fcport);
+               bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN);
+               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
                else
-                       bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
-                            enum bfa_pport_sm_event event)
+bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
+                            enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_QRESUME:
-               bfa_sm_set_state(pport, bfa_pport_sm_disabling);
-               bfa_pport_send_disable(pport);
+       case BFA_FCPORT_SM_QRESUME:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
+               bfa_fcport_send_disable(fcport);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
-               bfa_reqq_wcancel(&pport->reqq_wait);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
+               bfa_reqq_wcancel(&fcport->reqq_wait);
                break;
 
-       case BFA_PPORT_SM_DISABLE:
+       case BFA_FCPORT_SM_DISABLE:
                /**
                 * Already being disabled.
                 */
                break;
 
-       case BFA_PPORT_SM_LINKUP:
-       case BFA_PPORT_SM_LINKDOWN:
+       case BFA_FCPORT_SM_LINKUP:
+       case BFA_FCPORT_SM_LINKDOWN:
                /**
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
-               bfa_reqq_wcancel(&pport->reqq_wait);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
+               bfa_reqq_wcancel(&fcport->reqq_wait);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_disabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_FWRSP:
-               bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+       case BFA_FCPORT_SM_FWRSP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
                break;
 
-       case BFA_PPORT_SM_DISABLE:
+       case BFA_FCPORT_SM_DISABLE:
                /**
                 * Already being disabled.
                 */
                break;
 
-       case BFA_PPORT_SM_ENABLE:
-               if (bfa_pport_send_enable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+       case BFA_FCPORT_SM_ENABLE:
+               if (bfa_fcport_send_enable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait);
 
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                break;
 
-       case BFA_PPORT_SM_LINKUP:
-       case BFA_PPORT_SM_LINKDOWN:
+       case BFA_FCPORT_SM_LINKUP:
+       case BFA_FCPORT_SM_LINKDOWN:
                /**
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_disabled(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_START:
+       case BFA_FCPORT_SM_START:
                /**
                 * Ignore start event for a port that is disabled.
                 */
                break;
 
-       case BFA_PPORT_SM_STOP:
-               bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+       case BFA_FCPORT_SM_STOP:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                break;
 
-       case BFA_PPORT_SM_ENABLE:
-               if (bfa_pport_send_enable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+       case BFA_FCPORT_SM_ENABLE:
+               if (bfa_fcport_send_enable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait);
 
-               bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+               bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                             BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
-               bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
-       case BFA_PPORT_SM_DISABLE:
+       case BFA_FCPORT_SM_DISABLE:
                /**
                 * Already disabled.
                 */
                break;
 
-       case BFA_PPORT_SM_HWFAIL:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+       case BFA_FCPORT_SM_HWFAIL:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
                break;
 
        default:
-               bfa_sm_fault(pport->bfa, event);
+               bfa_sm_fault(fcport->bfa, event);
        }
 }
 
 static void
-bfa_pport_sm_stopped(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_START:
-               if (bfa_pport_send_enable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+       case BFA_FCPORT_SM_START:
+               if (bfa_fcport_send_enable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait);
                break;
 
        default:
@@ -574,16 +593,17 @@ bfa_pport_sm_stopped(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
  * Port is enabled. IOC is down/failed.
  */
 static void
-bfa_pport_sm_iocdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_START:
-               if (bfa_pport_send_enable(pport))
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+       case BFA_FCPORT_SM_START:
+               if (bfa_fcport_send_enable(fcport))
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
                else
-                       bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+                       bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait);
                break;
 
        default:
@@ -598,17 +618,18 @@ bfa_pport_sm_iocdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
  * Port is disabled. IOC is down/failed.
  */
 static void
-bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
+                       enum bfa_fcport_sm_event event)
 {
-       bfa_trc(pport->bfa, event);
+       bfa_trc(fcport->bfa, event);
 
        switch (event) {
-       case BFA_PPORT_SM_START:
-               bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+       case BFA_FCPORT_SM_START:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
                break;
 
-       case BFA_PPORT_SM_ENABLE:
-               bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+       case BFA_FCPORT_SM_ENABLE:
+               bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
                break;
 
        default:
@@ -619,41 +640,226 @@ bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
        }
 }
 
+/**
+ * Link state is down
+ */
+static void
+bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKUP:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf);
+               bfa_fcport_queue_cb(ln, BFA_PPORT_LINKUP);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is waiting for down notification
+ */
+static void
+bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKUP:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf);
+               break;
+
+       case BFA_FCPORT_LN_SM_NOTIFICATION:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is waiting for down notification and there is a pending up
+ */
+static void
+bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKDOWN:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf);
+               break;
+
+       case BFA_FCPORT_LN_SM_NOTIFICATION:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf);
+               bfa_fcport_queue_cb(ln, BFA_PPORT_LINKUP);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is up
+ */
+static void
+bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKDOWN:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf);
+               bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+               break;
 
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is waiting for up notification
+ */
+static void
+bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKDOWN:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf);
+               break;
+
+       case BFA_FCPORT_LN_SM_NOTIFICATION:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is waiting for up notification and there is a pending down
+ */
+static void
+bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln,
+               enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKUP:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_up_nf);
+               break;
+
+       case BFA_FCPORT_LN_SM_NOTIFICATION:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf);
+               bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
+
+/**
+ * Link state is waiting for up notification and there are pending down and up
+ */
+static void
+bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln,
+                       enum bfa_fcport_ln_sm_event event)
+{
+       bfa_trc(ln->fcport->bfa, event);
+
+       switch (event) {
+       case BFA_FCPORT_LN_SM_LINKDOWN:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf);
+               break;
+
+       case BFA_FCPORT_LN_SM_NOTIFICATION:
+               bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf);
+               bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+               break;
+
+       default:
+               bfa_sm_fault(ln->fcport->bfa, event);
+       }
+}
 
 /**
  *  bfa_pport_private
  */
 
 static void
-__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete)
+__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete)
 {
-       struct bfa_pport_s *pport = cbarg;
+       struct bfa_fcport_ln_s *ln = cbarg;
 
        if (complete)
-               pport->event_cbfn(pport->event_cbarg, pport->hcb_event);
+               ln->fcport->event_cbfn(ln->fcport->event_cbarg, ln->ln_event);
+       else
+               bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION);
 }
 
-#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), \
+static void
+bfa_fcport_callback(struct bfa_fcport_s *fcport, enum bfa_pport_linkstate event)
+{
+       if (fcport->bfa->fcs) {
+               fcport->event_cbfn(fcport->event_cbarg, event);
+               return;
+       }
+
+       switch (event) {
+       case BFA_PPORT_LINKUP:
+               bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKUP);
+               break;
+       case BFA_PPORT_LINKDOWN:
+               bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKDOWN);
+               break;
+       default:
+               bfa_assert(0);
+       }
+}
+
+static void
+bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_pport_linkstate event)
+{
+       ln->ln_event = event;
+       bfa_cb_queue(ln->fcport->bfa, &ln->ln_qe, __bfa_cb_fcport_event, ln);
+}
+
+#define FCPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_fcport_stats_u), \
                                                        BFA_CACHELINE_SZ))
 
 static void
-bfa_pport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
                  u32 *dm_len)
 {
-       *dm_len += PPORT_STATS_DMA_SZ;
+       *dm_len += FCPORT_STATS_DMA_SZ;
 }
 
 static void
-bfa_pport_qresume(void *cbarg)
+bfa_fcport_qresume(void *cbarg)
 {
-       struct bfa_pport_s *port = cbarg;
+       struct bfa_fcport_s *fcport = cbarg;
 
-       bfa_sm_send_event(port, BFA_PPORT_SM_QRESUME);
+       bfa_sm_send_event(fcport, BFA_FCPORT_SM_QRESUME);
 }
 
 static void
-bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
+bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo)
 {
        u8        *dm_kva;
        u64        dm_pa;
@@ -661,12 +867,12 @@ bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
        dm_kva = bfa_meminfo_dma_virt(meminfo);
        dm_pa = bfa_meminfo_dma_phys(meminfo);
 
-       pport->stats_kva = dm_kva;
-       pport->stats_pa = dm_pa;
-       pport->stats = (union bfa_pport_stats_u *)dm_kva;
+       fcport->stats_kva = dm_kva;
+       fcport->stats_pa = dm_pa;
+       fcport->stats = (union bfa_fcport_stats_u *)dm_kva;
 
-       dm_kva += PPORT_STATS_DMA_SZ;
-       dm_pa += PPORT_STATS_DMA_SZ;
+       dm_kva += FCPORT_STATS_DMA_SZ;
+       dm_pa += FCPORT_STATS_DMA_SZ;
 
        bfa_meminfo_dma_virt(meminfo) = dm_kva;
        bfa_meminfo_dma_phys(meminfo) = dm_pa;
@@ -676,18 +882,21 @@ bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
  * Memory initialization.
  */
 static void
-bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
                 struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
-       struct bfa_pport_cfg_s *port_cfg = &pport->cfg;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+       struct bfa_pport_cfg_s *port_cfg = &fcport->cfg;
+       struct bfa_fcport_ln_s *ln = &fcport->ln;
 
-       bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s));
-       pport->bfa = bfa;
+       bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s));
+       fcport->bfa = bfa;
+       ln->fcport = fcport;
 
-       bfa_pport_mem_claim(pport, meminfo);
+       bfa_fcport_mem_claim(fcport, meminfo);
 
-       bfa_sm_set_state(pport, bfa_pport_sm_uninit);
+       bfa_sm_set_state(fcport, bfa_fcport_sm_uninit);
+       bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
 
        /**
         * initialize and set default configuration
@@ -699,30 +908,30 @@ bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 
        port_cfg->trl_def_speed = BFA_PPORT_SPEED_1GBPS;
 
-       bfa_reqq_winit(&pport->reqq_wait, bfa_pport_qresume, pport);
+       bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport);
 }
 
 static void
-bfa_pport_initdone(struct bfa_s *bfa)
+bfa_fcport_initdone(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        /**
         * Initialize port attributes from IOC hardware data.
         */
-       bfa_pport_set_wwns(pport);
-       if (pport->cfg.maxfrsize == 0)
-               pport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
-       pport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
-       pport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
+       bfa_fcport_set_wwns(fcport);
+       if (fcport->cfg.maxfrsize == 0)
+               fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
+       fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
+       fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
 
-       bfa_assert(pport->cfg.maxfrsize);
-       bfa_assert(pport->cfg.rx_bbcredit);
-       bfa_assert(pport->speed_sup);
+       bfa_assert(fcport->cfg.maxfrsize);
+       bfa_assert(fcport->cfg.rx_bbcredit);
+       bfa_assert(fcport->speed_sup);
 }
 
 static void
-bfa_pport_detach(struct bfa_s *bfa)
+bfa_fcport_detach(struct bfa_s *bfa)
 {
 }
 
@@ -730,95 +939,97 @@ bfa_pport_detach(struct bfa_s *bfa)
  * Called when IOC is ready.
  */
 static void
-bfa_pport_start(struct bfa_s *bfa)
+bfa_fcport_start(struct bfa_s *bfa)
 {
-       bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_START);
+       bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START);
 }
 
 /**
  * Called before IOC is stopped.
  */
 static void
-bfa_pport_stop(struct bfa_s *bfa)
+bfa_fcport_stop(struct bfa_s *bfa)
 {
-       bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_STOP);
+       bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_STOP);
 }
 
 /**
  * Called when IOC failure is detected.
  */
 static void
-bfa_pport_iocdisable(struct bfa_s *bfa)
+bfa_fcport_iocdisable(struct bfa_s *bfa)
 {
-       bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_HWFAIL);
+       bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_HWFAIL);
 }
 
 static void
-bfa_pport_update_linkinfo(struct bfa_pport_s *pport)
+bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport)
 {
-       struct bfi_pport_event_s *pevent = pport->event_arg.i2hmsg.event;
+       struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event;
 
-       pport->speed = pevent->link_state.speed;
-       pport->topology = pevent->link_state.topology;
+       fcport->speed = pevent->link_state.speed;
+       fcport->topology = pevent->link_state.topology;
 
-       if (pport->topology == BFA_PPORT_TOPOLOGY_LOOP)
-               pport->myalpa = pevent->link_state.tl.loop_info.myalpa;
+       if (fcport->topology == BFA_PPORT_TOPOLOGY_LOOP)
+               fcport->myalpa =
+                       pevent->link_state.tl.loop_info.myalpa;
 
        /*
         * QoS Details
         */
-       bfa_os_assign(pport->qos_attr, pevent->link_state.qos_attr);
-       bfa_os_assign(pport->qos_vc_attr, pevent->link_state.qos_vc_attr);
+       bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr);
+       bfa_os_assign(fcport->qos_vc_attr, pevent->link_state.qos_vc_attr);
 
-       bfa_trc(pport->bfa, pport->speed);
-       bfa_trc(pport->bfa, pport->topology);
+       bfa_trc(fcport->bfa, fcport->speed);
+       bfa_trc(fcport->bfa, fcport->topology);
 }
 
 static void
-bfa_pport_reset_linkinfo(struct bfa_pport_s *pport)
+bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport)
 {
-       pport->speed = BFA_PPORT_SPEED_UNKNOWN;
-       pport->topology = BFA_PPORT_TOPOLOGY_NONE;
+       fcport->speed = BFA_PPORT_SPEED_UNKNOWN;
+       fcport->topology = BFA_PPORT_TOPOLOGY_NONE;
 }
 
 /**
  * Send port enable message to firmware.
  */
 static          bfa_boolean_t
-bfa_pport_send_enable(struct bfa_pport_s *port)
+bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
 {
-       struct bfi_pport_enable_req_s *m;
+       struct bfi_fcport_enable_req_s *m;
 
        /**
         * Increment message tag before queue check, so that responses to old
         * requests are discarded.
         */
-       port->msgtag++;
+       fcport->msgtag++;
 
        /**
         * check for room in queue to send request now
         */
-       m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+       m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
        if (!m) {
-               bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+               bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT,
+                                                       &fcport->reqq_wait);
                return BFA_FALSE;
        }
 
-       bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_ENABLE_REQ,
-                   bfa_lpuid(port->bfa));
-       m->nwwn = port->nwwn;
-       m->pwwn = port->pwwn;
-       m->port_cfg = port->cfg;
-       m->msgtag = port->msgtag;
-       m->port_cfg.maxfrsize = bfa_os_htons(port->cfg.maxfrsize);
-       bfa_dma_be_addr_set(m->stats_dma_addr, port->stats_pa);
-       bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_lo);
-       bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_hi);
+       bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ,
+                               bfa_lpuid(fcport->bfa));
+       m->nwwn = fcport->nwwn;
+       m->pwwn = fcport->pwwn;
+       m->port_cfg = fcport->cfg;
+       m->msgtag = fcport->msgtag;
+       m->port_cfg.maxfrsize = bfa_os_htons(fcport->cfg.maxfrsize);
+       bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa);
+       bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo);
+       bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi);
 
        /**
         * queue I/O message to firmware
         */
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+       bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
        return BFA_TRUE;
 }
 
@@ -826,74 +1037,226 @@ bfa_pport_send_enable(struct bfa_pport_s *port)
  * Send port disable message to firmware.
  */
 static          bfa_boolean_t
-bfa_pport_send_disable(struct bfa_pport_s *port)
+bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
 {
-       bfi_pport_disable_req_t *m;
+       struct bfi_fcport_req_s *m;
 
        /**
         * Increment message tag before queue check, so that responses to old
         * requests are discarded.
         */
-       port->msgtag++;
+       fcport->msgtag++;
 
        /**
         * check for room in queue to send request now
         */
-       m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+       m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
        if (!m) {
-               bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+               bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT,
+                                                       &fcport->reqq_wait);
                return BFA_FALSE;
        }
 
-       bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_DISABLE_REQ,
-                   bfa_lpuid(port->bfa));
-       m->msgtag = port->msgtag;
+       bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ,
+                       bfa_lpuid(fcport->bfa));
+       m->msgtag = fcport->msgtag;
 
        /**
         * queue I/O message to firmware
         */
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+       bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
 
        return BFA_TRUE;
 }
 
 static void
-bfa_pport_set_wwns(struct bfa_pport_s *port)
+bfa_fcport_set_wwns(struct bfa_fcport_s *fcport)
 {
-       port->pwwn = bfa_ioc_get_pwwn(&port->bfa->ioc);
-       port->nwwn = bfa_ioc_get_nwwn(&port->bfa->ioc);
+       fcport->pwwn = bfa_ioc_get_pwwn(&fcport->bfa->ioc);
+       fcport->nwwn = bfa_ioc_get_nwwn(&fcport->bfa->ioc);
 
-       bfa_trc(port->bfa, port->pwwn);
-       bfa_trc(port->bfa, port->nwwn);
+       bfa_trc(fcport->bfa, fcport->pwwn);
+       bfa_trc(fcport->bfa, fcport->nwwn);
 }
 
 static void
-bfa_port_send_txcredit(void *port_cbarg)
+bfa_fcport_send_txcredit(void *port_cbarg)
 {
 
-       struct bfa_pport_s *port = port_cbarg;
-       struct bfi_pport_set_svc_params_req_s *m;
+       struct bfa_fcport_s *fcport = port_cbarg;
+       struct bfi_fcport_set_svc_params_req_s *m;
 
        /**
         * check for room in queue to send request now
         */
-       m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+       m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
        if (!m) {
-               bfa_trc(port->bfa, port->cfg.tx_bbcredit);
+               bfa_trc(fcport->bfa, fcport->cfg.tx_bbcredit);
                return;
        }
 
-       bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_SET_SVC_PARAMS_REQ,
-                   bfa_lpuid(port->bfa));
-       m->tx_bbcredit = bfa_os_htons((u16) port->cfg.tx_bbcredit);
+       bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ,
+                       bfa_lpuid(fcport->bfa));
+       m->tx_bbcredit = bfa_os_htons((u16) fcport->cfg.tx_bbcredit);
 
        /**
         * queue I/O message to firmware
         */
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+       bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
 }
 
+static void
+bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d,
+       struct bfa_qos_stats_s *s)
+{
+       u32     *dip = (u32 *) d;
+       u32     *sip = (u32 *) s;
+       int             i;
+
+       /* Now swap the 32 bit fields */
+       for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i)
+               dip[i] = bfa_os_ntohl(sip[i]);
+}
 
+static void
+bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
+       struct bfa_fcoe_stats_s *s)
+{
+       u32     *dip = (u32 *) d;
+       u32     *sip = (u32 *) s;
+       int             i;
+
+       for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32));
+               i = i + 2) {
+#ifdef __BIGENDIAN
+               dip[i] = bfa_os_ntohl(sip[i]);
+               dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
+#else
+               dip[i] = bfa_os_ntohl(sip[i + 1]);
+               dip[i + 1] = bfa_os_ntohl(sip[i]);
+#endif
+       }
+}
+
+static void
+__bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_fcport_s *fcport = cbarg;
+
+       if (complete) {
+               if (fcport->stats_status == BFA_STATUS_OK) {
+
+                       /* Swap FC QoS or FCoE stats */
+                       if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
+                               bfa_fcport_qos_stats_swap(
+                                       &fcport->stats_ret->fcqos,
+                                       &fcport->stats->fcqos);
+                       else
+                               bfa_fcport_fcoe_stats_swap(
+                                       &fcport->stats_ret->fcoe,
+                                       &fcport->stats->fcoe);
+               }
+               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+       } else {
+               fcport->stats_busy = BFA_FALSE;
+               fcport->stats_status = BFA_STATUS_OK;
+       }
+}
+
+static void
+bfa_fcport_stats_get_timeout(void *cbarg)
+{
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+
+       bfa_trc(fcport->bfa, fcport->stats_qfull);
+
+       if (fcport->stats_qfull) {
+               bfa_reqq_wcancel(&fcport->stats_reqq_wait);
+               fcport->stats_qfull = BFA_FALSE;
+       }
+
+       fcport->stats_status = BFA_STATUS_ETIMER;
+       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get,
+               fcport);
+}
+
+static void
+bfa_fcport_send_stats_get(void *cbarg)
+{
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+       struct bfi_fcport_req_s *msg;
+
+       msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
+
+       if (!msg) {
+               fcport->stats_qfull = BFA_TRUE;
+               bfa_reqq_winit(&fcport->stats_reqq_wait,
+                               bfa_fcport_send_stats_get, fcport);
+               bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT,
+                               &fcport->stats_reqq_wait);
+               return;
+       }
+       fcport->stats_qfull = BFA_FALSE;
+
+       bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+       bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ,
+               bfa_lpuid(fcport->bfa));
+       bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
+}
+
+static void
+__bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_fcport_s *fcport = cbarg;
+
+       if (complete) {
+               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+       } else {
+               fcport->stats_busy = BFA_FALSE;
+               fcport->stats_status = BFA_STATUS_OK;
+       }
+}
+
+static void
+bfa_fcport_stats_clr_timeout(void *cbarg)
+{
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+
+       bfa_trc(fcport->bfa, fcport->stats_qfull);
+
+       if (fcport->stats_qfull) {
+               bfa_reqq_wcancel(&fcport->stats_reqq_wait);
+               fcport->stats_qfull = BFA_FALSE;
+       }
+
+       fcport->stats_status = BFA_STATUS_ETIMER;
+       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
+                       __bfa_cb_fcport_stats_clr, fcport);
+}
+
+static void
+bfa_fcport_send_stats_clear(void *cbarg)
+{
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+       struct bfi_fcport_req_s *msg;
+
+       msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
+
+       if (!msg) {
+               fcport->stats_qfull = BFA_TRUE;
+               bfa_reqq_winit(&fcport->stats_reqq_wait,
+                               bfa_fcport_send_stats_clear, fcport);
+               bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT,
+                               &fcport->stats_reqq_wait);
+               return;
+       }
+       fcport->stats_qfull = BFA_FALSE;
+
+       bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+       bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ,
+                       bfa_lpuid(fcport->bfa));
+       bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
+}
 
 /**
  *  bfa_pport_public
@@ -903,32 +1266,32 @@ bfa_port_send_txcredit(void *port_cbarg)
  * Firmware message handler.
  */
 void
-bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
-       union bfi_pport_i2h_msg_u i2hmsg;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+       union bfi_fcport_i2h_msg_u i2hmsg;
 
        i2hmsg.msg = msg;
-       pport->event_arg.i2hmsg = i2hmsg;
+       fcport->event_arg.i2hmsg = i2hmsg;
 
        switch (msg->mhdr.msg_id) {
-       case BFI_PPORT_I2H_ENABLE_RSP:
-               if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
-                       bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+       case BFI_FCPORT_I2H_ENABLE_RSP:
+               if (fcport->msgtag == i2hmsg.penable_rsp->msgtag)
+                       bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
                break;
 
-       case BFI_PPORT_I2H_DISABLE_RSP:
-               if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
-                       bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+       case BFI_FCPORT_I2H_DISABLE_RSP:
+               if (fcport->msgtag == i2hmsg.penable_rsp->msgtag)
+                       bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
                break;
 
-       case BFI_PPORT_I2H_EVENT:
+       case BFI_FCPORT_I2H_EVENT:
                switch (i2hmsg.event->link_state.linkstate) {
                case BFA_PPORT_LINKUP:
-                       bfa_sm_send_event(pport, BFA_PPORT_SM_LINKUP);
+                       bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKUP);
                        break;
                case BFA_PPORT_LINKDOWN:
-                       bfa_sm_send_event(pport, BFA_PPORT_SM_LINKDOWN);
+                       bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKDOWN);
                        break;
                case BFA_PPORT_TRUNK_LINKDOWN:
                        /** todo: event notification */
@@ -936,42 +1299,40 @@ bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
                }
                break;
 
-       case BFI_PPORT_I2H_GET_STATS_RSP:
-       case BFI_PPORT_I2H_GET_QOS_STATS_RSP:
+       case BFI_FCPORT_I2H_STATS_GET_RSP:
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (pport->stats_busy == BFA_FALSE
-                   || pport->stats_status == BFA_STATUS_ETIMER)
+               if (fcport->stats_busy == BFA_FALSE ||
+                       fcport->stats_status == BFA_STATUS_ETIMER)
                        break;
 
-               bfa_timer_stop(&pport->timer);
-               pport->stats_status = i2hmsg.getstats_rsp->status;
-               bfa_cb_queue(pport->bfa, &pport->hcb_qe, __bfa_cb_port_stats,
-                            pport);
+               bfa_timer_stop(&fcport->timer);
+               fcport->stats_status = i2hmsg.pstatsget_rsp->status;
+               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
+                               __bfa_cb_fcport_stats_get, fcport);
                break;
-       case BFI_PPORT_I2H_CLEAR_STATS_RSP:
-       case BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP:
+
+       case BFI_FCPORT_I2H_STATS_CLEAR_RSP:
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (pport->stats_busy == BFA_FALSE
-                   || pport->stats_status == BFA_STATUS_ETIMER)
+               if (fcport->stats_busy == BFA_FALSE ||
+                       fcport->stats_status == BFA_STATUS_ETIMER)
                        break;
 
-               bfa_timer_stop(&pport->timer);
-               pport->stats_status = BFA_STATUS_OK;
-               bfa_cb_queue(pport->bfa, &pport->hcb_qe,
-                            __bfa_cb_port_stats_clr, pport);
+               bfa_timer_stop(&fcport->timer);
+               fcport->stats_status = BFA_STATUS_OK;
+               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
+                               __bfa_cb_fcport_stats_clr, fcport);
                break;
 
        default:
                bfa_assert(0);
+       break;
        }
 }
 
-
-
 /**
  *  bfa_pport_api
  */
@@ -980,35 +1341,35 @@ bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
  * Registered callback for port events.
  */
 void
-bfa_pport_event_register(struct bfa_s *bfa,
+bfa_fcport_event_register(struct bfa_s *bfa,
                         void (*cbfn) (void *cbarg, bfa_pport_event_t event),
                         void *cbarg)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       pport->event_cbfn = cbfn;
-       pport->event_cbarg = cbarg;
+       fcport->event_cbfn = cbfn;
+       fcport->event_cbarg = cbarg;
 }
 
 bfa_status_t
-bfa_pport_enable(struct bfa_s *bfa)
+bfa_fcport_enable(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (pport->diag_busy)
+       if (fcport->diag_busy)
                return BFA_STATUS_DIAG_BUSY;
        else if (bfa_sm_cmp_state
-                (BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait))
+                (BFA_FCPORT_MOD(bfa), bfa_fcport_sm_disabling_qwait))
                return BFA_STATUS_DEVBUSY;
 
-       bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
+       bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_ENABLE);
        return BFA_STATUS_OK;
 }
 
 bfa_status_t
-bfa_pport_disable(struct bfa_s *bfa)
+bfa_fcport_disable(struct bfa_s *bfa)
 {
-       bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_DISABLE);
+       bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE);
        return BFA_STATUS_OK;
 }
 
@@ -1016,18 +1377,18 @@ bfa_pport_disable(struct bfa_s *bfa)
  * Configure port speed.
  */
 bfa_status_t
-bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, speed);
 
-       if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > pport->speed_sup)) {
-               bfa_trc(bfa, pport->speed_sup);
+       if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > fcport->speed_sup)) {
+               bfa_trc(bfa, fcport->speed_sup);
                return BFA_STATUS_UNSUPP_SPEED;
        }
 
-       pport->cfg.speed = speed;
+       fcport->cfg.speed = speed;
 
        return BFA_STATUS_OK;
 }
@@ -1036,23 +1397,23 @@ bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
  * Get current speed.
  */
 enum bfa_pport_speed
-bfa_pport_get_speed(struct bfa_s *bfa)
+bfa_fcport_get_speed(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->speed;
+       return fcport->speed;
 }
 
 /**
  * Configure port topology.
  */
 bfa_status_t
-bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
+bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, topology);
-       bfa_trc(bfa, pport->cfg.topology);
+       bfa_trc(bfa, fcport->cfg.topology);
 
        switch (topology) {
        case BFA_PPORT_TOPOLOGY_P2P:
@@ -1064,7 +1425,7 @@ bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
                return BFA_STATUS_EINVAL;
        }
 
-       pport->cfg.topology = topology;
+       fcport->cfg.topology = topology;
        return BFA_STATUS_OK;
 }
 
@@ -1072,64 +1433,64 @@ bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
  * Get current topology.
  */
 enum bfa_pport_topology
-bfa_pport_get_topology(struct bfa_s *bfa)
+bfa_fcport_get_topology(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->topology;
+       return fcport->topology;
 }
 
 bfa_status_t
-bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
+bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, alpa);
-       bfa_trc(bfa, pport->cfg.cfg_hardalpa);
-       bfa_trc(bfa, pport->cfg.hardalpa);
+       bfa_trc(bfa, fcport->cfg.cfg_hardalpa);
+       bfa_trc(bfa, fcport->cfg.hardalpa);
 
-       pport->cfg.cfg_hardalpa = BFA_TRUE;
-       pport->cfg.hardalpa = alpa;
+       fcport->cfg.cfg_hardalpa = BFA_TRUE;
+       fcport->cfg.hardalpa = alpa;
 
        return BFA_STATUS_OK;
 }
 
 bfa_status_t
-bfa_pport_clr_hardalpa(struct bfa_s *bfa)
+bfa_fcport_clr_hardalpa(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       bfa_trc(bfa, pport->cfg.cfg_hardalpa);
-       bfa_trc(bfa, pport->cfg.hardalpa);
+       bfa_trc(bfa, fcport->cfg.cfg_hardalpa);
+       bfa_trc(bfa, fcport->cfg.hardalpa);
 
-       pport->cfg.cfg_hardalpa = BFA_FALSE;
+       fcport->cfg.cfg_hardalpa = BFA_FALSE;
        return BFA_STATUS_OK;
 }
 
 bfa_boolean_t
-bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa)
+bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       *alpa = port->cfg.hardalpa;
-       return port->cfg.cfg_hardalpa;
+       *alpa = fcport->cfg.hardalpa;
+       return fcport->cfg.cfg_hardalpa;
 }
 
 u8
-bfa_pport_get_myalpa(struct bfa_s *bfa)
+bfa_fcport_get_myalpa(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->myalpa;
+       return fcport->myalpa;
 }
 
 bfa_status_t
-bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
+bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, maxfrsize);
-       bfa_trc(bfa, pport->cfg.maxfrsize);
+       bfa_trc(bfa, fcport->cfg.maxfrsize);
 
        /*
         * with in range
@@ -1143,41 +1504,41 @@ bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
        if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1)))
                return BFA_STATUS_INVLD_DFSZ;
 
-       pport->cfg.maxfrsize = maxfrsize;
+       fcport->cfg.maxfrsize = maxfrsize;
        return BFA_STATUS_OK;
 }
 
 u16
-bfa_pport_get_maxfrsize(struct bfa_s *bfa)
+bfa_fcport_get_maxfrsize(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->cfg.maxfrsize;
+       return fcport->cfg.maxfrsize;
 }
 
 u32
-bfa_pport_mypid(struct bfa_s *bfa)
+bfa_fcport_mypid(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->mypid;
+       return fcport->mypid;
 }
 
 u8
-bfa_pport_get_rx_bbcredit(struct bfa_s *bfa)
+bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return port->cfg.rx_bbcredit;
+       return fcport->cfg.rx_bbcredit;
 }
 
 void
-bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
+bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       port->cfg.tx_bbcredit = (u8) tx_bbcredit;
-       bfa_port_send_txcredit(port);
+       fcport->cfg.tx_bbcredit = (u8) tx_bbcredit;
+       bfa_fcport_send_txcredit(fcport);
 }
 
 /**
@@ -1185,302 +1546,192 @@ bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
  */
 
 wwn_t
-bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node)
+bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
        if (node)
-               return pport->nwwn;
+               return fcport->nwwn;
        else
-               return pport->pwwn;
+               return fcport->pwwn;
 }
 
 void
-bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
+bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
 
-       attr->nwwn = pport->nwwn;
-       attr->pwwn = pport->pwwn;
+       attr->nwwn = fcport->nwwn;
+       attr->pwwn = fcport->pwwn;
 
-       bfa_os_memcpy(&attr->pport_cfg, &pport->cfg,
+       bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg,
                      sizeof(struct bfa_pport_cfg_s));
        /*
         * speed attributes
         */
-       attr->pport_cfg.speed = pport->cfg.speed;
-       attr->speed_supported = pport->speed_sup;
-       attr->speed = pport->speed;
+       attr->pport_cfg.speed = fcport->cfg.speed;
+       attr->speed_supported = fcport->speed_sup;
+       attr->speed = fcport->speed;
        attr->cos_supported = FC_CLASS_3;
 
        /*
         * topology attributes
         */
-       attr->pport_cfg.topology = pport->cfg.topology;
-       attr->topology = pport->topology;
+       attr->pport_cfg.topology = fcport->cfg.topology;
+       attr->topology = fcport->topology;
 
        /*
         * beacon attributes
         */
-       attr->beacon = pport->beacon;
-       attr->link_e2e_beacon = pport->link_e2e_beacon;
-       attr->plog_enabled = bfa_plog_get_setting(pport->bfa->plog);
+       attr->beacon = fcport->beacon;
+       attr->link_e2e_beacon = fcport->link_e2e_beacon;
+       attr->plog_enabled = bfa_plog_get_setting(fcport->bfa->plog);
 
        attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
        attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
-       attr->port_state = bfa_sm_to_state(hal_pport_sm_table, pport->sm);
-       if (bfa_ioc_is_disabled(&pport->bfa->ioc))
+       attr->port_state = bfa_sm_to_state(hal_pport_sm_table, fcport->sm);
+       if (bfa_ioc_is_disabled(&fcport->bfa->ioc))
                attr->port_state = BFA_PPORT_ST_IOCDIS;
-       else if (bfa_ioc_fw_mismatch(&pport->bfa->ioc))
+       else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
                attr->port_state = BFA_PPORT_ST_FWMISMATCH;
 }
 
-static void
-bfa_port_stats_query(void *cbarg)
-{
-       struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
-       bfi_pport_get_stats_req_t *msg;
-
-       msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
-
-       if (!msg) {
-               port->stats_qfull = BFA_TRUE;
-               bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_query,
-                              port);
-               bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
-               return;
-       }
-       port->stats_qfull = BFA_FALSE;
-
-       bfa_os_memset(msg, 0, sizeof(bfi_pport_get_stats_req_t));
-       bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_GET_STATS_REQ,
-                   bfa_lpuid(port->bfa));
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
-
-       return;
-}
-
-static void
-bfa_port_stats_clear(void *cbarg)
-{
-       struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
-       bfi_pport_clear_stats_req_t *msg;
-
-       msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+#define BFA_FCPORT_STATS_TOV   1000
 
-       if (!msg) {
-               port->stats_qfull = BFA_TRUE;
-               bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_clear,
-                              port);
-               bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
-               return;
-       }
-       port->stats_qfull = BFA_FALSE;
-
-       bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_stats_req_t));
-       bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_STATS_REQ,
-                   bfa_lpuid(port->bfa));
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
-       return;
-}
-
-static void
-bfa_port_qos_stats_clear(void *cbarg)
+/**
+ * Fetch port attributes (FCQoS or FCoE).
+ */
+bfa_status_t
+bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
+                   bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
-       bfi_pport_clear_qos_stats_req_t *msg;
-
-       msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (!msg) {
-               port->stats_qfull = BFA_TRUE;
-               bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_qos_stats_clear,
-                              port);
-               bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
-               return;
+       if (fcport->stats_busy) {
+               bfa_trc(bfa, fcport->stats_busy);
+               return BFA_STATUS_DEVBUSY;
        }
-       port->stats_qfull = BFA_FALSE;
 
-       bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_qos_stats_req_t));
-       bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ,
-                   bfa_lpuid(port->bfa));
-       bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
-       return;
-}
-
-static void
-bfa_pport_stats_swap(union bfa_pport_stats_u *d, union bfa_pport_stats_u *s)
-{
-       u32       *dip = (u32 *) d;
-       u32       *sip = (u32 *) s;
-       int             i;
+       fcport->stats_busy  = BFA_TRUE;
+       fcport->stats_ret   = stats;
+       fcport->stats_cbfn  = cbfn;
+       fcport->stats_cbarg = cbarg;
 
-       /*
-        * Do 64 bit fields swap first
-        */
-       for (i = 0;
-            i <
-            ((sizeof(union bfa_pport_stats_u) -
-              sizeof(struct bfa_qos_stats_s)) / sizeof(u32)); i = i + 2) {
-#ifdef __BIGENDIAN
-               dip[i] = bfa_os_ntohl(sip[i]);
-               dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
-#else
-               dip[i] = bfa_os_ntohl(sip[i + 1]);
-               dip[i + 1] = bfa_os_ntohl(sip[i]);
-#endif
-       }
+       bfa_fcport_send_stats_get(fcport);
 
-       /*
-        * Now swap the 32 bit fields
-        */
-       for (; i < (sizeof(union bfa_pport_stats_u) / sizeof(u32)); ++i)
-               dip[i] = bfa_os_ntohl(sip[i]);
+       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout,
+               fcport, BFA_FCPORT_STATS_TOV);
+       return BFA_STATUS_OK;
 }
 
-static void
-__bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete)
+/**
+ * Reset port statistics (FCQoS or FCoE).
+ */
+bfa_status_t
+bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = cbarg;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (complete) {
-               port->stats_cbfn(port->stats_cbarg, port->stats_status);
-       } else {
-               port->stats_busy = BFA_FALSE;
-               port->stats_status = BFA_STATUS_OK;
+       if (fcport->stats_busy) {
+               bfa_trc(bfa, fcport->stats_busy);
+               return BFA_STATUS_DEVBUSY;
        }
-}
-
-static void
-bfa_port_stats_clr_timeout(void *cbarg)
-{
-       struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
 
-       bfa_trc(port->bfa, port->stats_qfull);
+       fcport->stats_busy = BFA_TRUE;
+       fcport->stats_cbfn = cbfn;
+       fcport->stats_cbarg = cbarg;
 
-       if (port->stats_qfull) {
-               bfa_reqq_wcancel(&port->stats_reqq_wait);
-               port->stats_qfull = BFA_FALSE;
-       }
+       bfa_fcport_send_stats_clear(fcport);
 
-       port->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats_clr, port);
+       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout,
+                       fcport, BFA_FCPORT_STATS_TOV);
+       return BFA_STATUS_OK;
 }
 
-static void
-__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete)
+/**
+ * Fetch FCQoS port statistics
+ */
+bfa_status_t
+bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
+       bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = cbarg;
+       /* Meaningful only for FC mode */
+       bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
 
-       if (complete) {
-               if (port->stats_status == BFA_STATUS_OK)
-                       bfa_pport_stats_swap(port->stats_ret, port->stats);
-               port->stats_cbfn(port->stats_cbarg, port->stats_status);
-       } else {
-               port->stats_busy = BFA_FALSE;
-               port->stats_status = BFA_STATUS_OK;
-       }
+       return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
 }
 
-static void
-bfa_port_stats_timeout(void *cbarg)
+/**
+ * Reset FCoE port statistics
+ */
+bfa_status_t
+bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
-
-       bfa_trc(port->bfa, port->stats_qfull);
+       /* Meaningful only for FC mode */
+       bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
 
-       if (port->stats_qfull) {
-               bfa_reqq_wcancel(&port->stats_reqq_wait);
-               port->stats_qfull = BFA_FALSE;
-       }
-
-       port->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats, port);
+       return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
 }
 
-#define BFA_PORT_STATS_TOV     1000
-
 /**
- * Fetch port attributes.
+ * Fetch FCQoS port statistics
  */
 bfa_status_t
-bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
-                   bfa_cb_pport_t cbfn, void *cbarg)
+bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
+       bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
-
-       if (port->stats_busy) {
-               bfa_trc(bfa, port->stats_busy);
-               return BFA_STATUS_DEVBUSY;
-       }
-
-       port->stats_busy = BFA_TRUE;
-       port->stats_ret = stats;
-       port->stats_cbfn = cbfn;
-       port->stats_cbarg = cbarg;
-
-       bfa_port_stats_query(port);
+       /* Meaningful only for FCoE mode */
+       bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
 
-       bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
-                       BFA_PORT_STATS_TOV);
-       return BFA_STATUS_OK;
+       return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
 }
 
+/**
+ * Reset FCoE port statistics
+ */
 bfa_status_t
-bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
+bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
-
-       if (port->stats_busy) {
-               bfa_trc(bfa, port->stats_busy);
-               return BFA_STATUS_DEVBUSY;
-       }
-
-       port->stats_busy = BFA_TRUE;
-       port->stats_cbfn = cbfn;
-       port->stats_cbarg = cbarg;
-
-       bfa_port_stats_clear(port);
+       /* Meaningful only for FCoE mode */
+       bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
 
-       bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
-                       BFA_PORT_STATS_TOV);
-       return BFA_STATUS_OK;
+       return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
 }
 
 bfa_status_t
-bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap)
+bfa_fcport_trunk_enable(struct bfa_s *bfa, u8 bitmap)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, bitmap);
-       bfa_trc(bfa, pport->cfg.trunked);
-       bfa_trc(bfa, pport->cfg.trunk_ports);
+       bfa_trc(bfa, fcport->cfg.trunked);
+       bfa_trc(bfa, fcport->cfg.trunk_ports);
 
        if (!bitmap || (bitmap & (bitmap - 1)))
                return BFA_STATUS_EINVAL;
 
-       pport->cfg.trunked = BFA_TRUE;
-       pport->cfg.trunk_ports = bitmap;
+       fcport->cfg.trunked = BFA_TRUE;
+       fcport->cfg.trunk_ports = bitmap;
 
        return BFA_STATUS_OK;
 }
 
 void
-bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
+bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       qos_attr->state = bfa_os_ntohl(pport->qos_attr.state);
-       qos_attr->total_bb_cr = bfa_os_ntohl(pport->qos_attr.total_bb_cr);
+       qos_attr->state = bfa_os_ntohl(fcport->qos_attr.state);
+       qos_attr->total_bb_cr = bfa_os_ntohl(fcport->qos_attr.total_bb_cr);
 }
 
 void
-bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
                          struct bfa_qos_vc_attr_s *qos_vc_attr)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
-       struct bfa_qos_vc_attr_s *bfa_vc_attr = &pport->qos_vc_attr;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+       struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
        u32        i = 0;
 
        qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
@@ -1503,119 +1754,89 @@ bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
 }
 
 /**
- * Fetch QoS Stats.
- */
-bfa_status_t
-bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
-                       bfa_cb_pport_t cbfn, void *cbarg)
-{
-       /*
-        * QoS stats is embedded in port stats
-        */
-       return bfa_pport_get_stats(bfa, stats, cbfn, cbarg);
-}
-
-bfa_status_t
-bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
-{
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
-
-       if (port->stats_busy) {
-               bfa_trc(bfa, port->stats_busy);
-               return BFA_STATUS_DEVBUSY;
-       }
-
-       port->stats_busy = BFA_TRUE;
-       port->stats_cbfn = cbfn;
-       port->stats_cbarg = cbarg;
-
-       bfa_port_qos_stats_clear(port);
-
-       bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
-                       BFA_PORT_STATS_TOV);
-       return BFA_STATUS_OK;
-}
-
-/**
  * Fetch port attributes.
  */
 bfa_status_t
-bfa_pport_trunk_disable(struct bfa_s *bfa)
+bfa_fcport_trunk_disable(struct bfa_s *bfa)
 {
        return BFA_STATUS_OK;
 }
 
 bfa_boolean_t
-bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap)
+bfa_fcport_trunk_query(struct bfa_s *bfa, u32 *bitmap)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       *bitmap = port->cfg.trunk_ports;
-       return port->cfg.trunked;
+       *bitmap = fcport->cfg.trunk_ports;
+       return fcport->cfg.trunked;
 }
 
 bfa_boolean_t
-bfa_pport_is_disabled(struct bfa_s *bfa)
+bfa_fcport_is_disabled(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
+       return bfa_sm_to_state(hal_pport_sm_table, fcport->sm) ==
                BFA_PPORT_ST_DISABLED;
 
 }
 
 bfa_boolean_t
-bfa_pport_is_ratelim(struct bfa_s *bfa)
+bfa_fcport_is_ratelim(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       return pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE;
+       return fcport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE;
 
 }
 
 void
-bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
+bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+       enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa);
 
        bfa_trc(bfa, on_off);
-       bfa_trc(bfa, pport->cfg.qos_enabled);
+       bfa_trc(bfa, fcport->cfg.qos_enabled);
+
+       bfa_trc(bfa, ioc_type);
 
-       pport->cfg.qos_enabled = on_off;
+       if (ioc_type == BFA_IOC_TYPE_FC)
+               fcport->cfg.qos_enabled = on_off;
 }
 
 void
-bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
+bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, on_off);
-       bfa_trc(bfa, pport->cfg.ratelimit);
+       bfa_trc(bfa, fcport->cfg.ratelimit);
 
-       pport->cfg.ratelimit = on_off;
-       if (pport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN)
-               pport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS;
+       fcport->cfg.ratelimit = on_off;
+       if (fcport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN)
+               fcport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS;
 }
 
 /**
  * Configure default minimum ratelim speed
  */
 bfa_status_t
-bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, speed);
 
        /*
         * Auto and speeds greater than the supported speed, are invalid
         */
-       if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > pport->speed_sup)) {
-               bfa_trc(bfa, pport->speed_sup);
+       if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > fcport->speed_sup)) {
+               bfa_trc(bfa, fcport->speed_sup);
                return BFA_STATUS_UNSUPP_SPEED;
        }
 
-       pport->cfg.trl_def_speed = speed;
+       fcport->cfg.trl_def_speed = speed;
 
        return BFA_STATUS_OK;
 }
@@ -1624,45 +1845,45 @@ bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
  * Get default minimum ratelim speed
  */
 enum bfa_pport_speed
-bfa_pport_get_ratelim_speed(struct bfa_s *bfa)
+bfa_fcport_get_ratelim_speed(struct bfa_s *bfa)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       bfa_trc(bfa, pport->cfg.trl_def_speed);
-       return pport->cfg.trl_def_speed;
+       bfa_trc(bfa, fcport->cfg.trl_def_speed);
+       return fcport->cfg.trl_def_speed;
 
 }
 
 void
-bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status)
+bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, status);
-       bfa_trc(bfa, pport->diag_busy);
+       bfa_trc(bfa, fcport->diag_busy);
 
-       pport->diag_busy = status;
+       fcport->diag_busy = status;
 }
 
 void
-bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+bfa_fcport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
                 bfa_boolean_t link_e2e_beacon)
 {
-       struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        bfa_trc(bfa, beacon);
        bfa_trc(bfa, link_e2e_beacon);
-       bfa_trc(bfa, pport->beacon);
-       bfa_trc(bfa, pport->link_e2e_beacon);
+       bfa_trc(bfa, fcport->beacon);
+       bfa_trc(bfa, fcport->link_e2e_beacon);
 
-       pport->beacon = beacon;
-       pport->link_e2e_beacon = link_e2e_beacon;
+       fcport->beacon = beacon;
+       fcport->link_e2e_beacon = link_e2e_beacon;
 }
 
 bfa_boolean_t
-bfa_pport_is_linkup(struct bfa_s *bfa)
+bfa_fcport_is_linkup(struct bfa_s *bfa)
 {
-       return bfa_sm_cmp_state(BFA_PORT_MOD(bfa), bfa_pport_sm_linkup);
+       return bfa_sm_cmp_state(BFA_FCPORT_MOD(bfa), bfa_fcport_sm_linkup);
 }
 
 
index 7cb39a3..3516172 100644 (file)
@@ -36,6 +36,7 @@
  * FCS sub-modules
  */
 struct bfa_fcs_mod_s {
+       void            (*attach) (struct bfa_fcs_s *fcs);
        void            (*modinit) (struct bfa_fcs_s *fcs);
        void            (*modexit) (struct bfa_fcs_s *fcs);
 };
@@ -43,12 +44,10 @@ struct bfa_fcs_mod_s {
 #define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
 
 static struct bfa_fcs_mod_s fcs_modules[] = {
-       BFA_FCS_MODULE(bfa_fcs_pport),
-       BFA_FCS_MODULE(bfa_fcs_uf),
-       BFA_FCS_MODULE(bfa_fcs_fabric),
-       BFA_FCS_MODULE(bfa_fcs_vport),
-       BFA_FCS_MODULE(bfa_fcs_rport),
-       BFA_FCS_MODULE(bfa_fcs_fcpim),
+       { bfa_fcs_pport_attach, NULL, NULL },
+       { bfa_fcs_uf_attach, NULL, NULL },
+       { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit,
+        bfa_fcs_fabric_modexit },
 };
 
 /**
@@ -71,16 +70,10 @@ bfa_fcs_exit_comp(void *fcs_cbarg)
  */
 
 /**
- *             FCS instance initialization.
- *
- *     param[in]               fcs             FCS instance
- *     param[in]               bfa             BFA instance
- *     param[in]               bfad            BFA driver instance
- *
- *     return None
+ * fcs attach -- called once to initialize data structures at driver attach time
  */
 void
-bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
                        bfa_boolean_t min_cfg)
 {
        int             i;
@@ -95,7 +88,24 @@ bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
 
        for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
                mod = &fcs_modules[i];
-               mod->modinit(fcs);
+               if (mod->attach)
+                       mod->attach(fcs);
+       }
+}
+
+/**
+ * fcs initialization, called once after bfa initialization is complete
+ */
+void
+bfa_fcs_init(struct bfa_fcs_s *fcs)
+{
+       int             i;
+       struct bfa_fcs_mod_s  *mod;
+
+       for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
+               mod = &fcs_modules[i];
+               if (mod->modinit)
+                       mod->modinit(fcs);
        }
 }
 
@@ -127,6 +137,23 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
 }
 
 /**
+ *      @brief
+ *              FCS FDMI Driver Parameter Initialization
+ *
+ *      @param[in]              fcs             FCS instance
+ *      @param[in]              fdmi_enable     TRUE/FALSE
+ *
+ *      @return None
+ */
+void
+bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable)
+{
+
+       fcs->fdmi_enabled = fdmi_enable;
+
+}
+
+/**
  *             FCS instance cleanup and exit.
  *
  *     param[in]               fcs                     FCS instance
@@ -143,10 +170,12 @@ bfa_fcs_exit(struct bfa_fcs_s *fcs)
        nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
 
        for (i = 0; i < nmods; i++) {
-               bfa_wc_up(&fcs->wc);
 
                mod = &fcs_modules[i];
-               mod->modexit(fcs);
+               if (mod->modexit) {
+                       bfa_wc_up(&fcs->wc);
+                       mod->modexit(fcs);
+               }
        }
 
        bfa_wc_wait(&fcs->wc);
index c7ab257..7c1251c 100644 (file)
@@ -114,7 +114,7 @@ bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -136,7 +136,7 @@ bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -176,7 +176,7 @@ bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -214,7 +214,7 @@ bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -234,7 +234,7 @@ bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -263,30 +263,8 @@ bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
 
        bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
 
-       switch (event) {
-       case BFA_LPORT_AEN_ONLINE:
-               bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_OFFLINE:
-               bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_NEW:
-               bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_DELETE:
-               bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_DISCONNECT:
-               bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr,
+               role_str[role/2]);
 
        aen_data.lport.vf_id = port->fabric->vf_id;
        aen_data.lport.roles = role;
@@ -873,36 +851,46 @@ bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
 }
 
 /**
- * Logical port initialization of base or virtual port.
- * Called by fabric for base port or by vport for virtual ports.
+ * Attach time initialization of logical ports.
  */
 void
-bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
-                  u16 vf_id, struct bfa_port_cfg_s *port_cfg,
-                  struct bfa_fcs_vport_s *vport)
+bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
+               uint16_t vf_id, struct bfa_fcs_vport_s *vport)
 {
        lport->fcs = fcs;
        lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
-       bfa_os_assign(lport->port_cfg, *port_cfg);
        lport->vport = vport;
        lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
                         bfa_lps_get_tag(lport->fabric->lps);
 
        INIT_LIST_HEAD(&lport->rport_q);
        lport->num_rports = 0;
+}
+
+/**
+ * Logical port initialization of base or virtual port.
+ * Called by fabric for base port or by vport for virtual ports.
+ */
 
-       lport->bfad_port =
-               bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles,
+void
+bfa_fcs_lport_init(struct bfa_fcs_port_s *lport,
+               struct bfa_port_cfg_s *port_cfg)
+{
+       struct bfa_fcs_vport_s *vport = lport->vport;
+
+       bfa_os_assign(lport->port_cfg, *port_cfg);
+
+       lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport,
+                               lport->port_cfg.roles,
                                lport->fabric->vf_drv,
                                vport ? vport->vport_drv : NULL);
+
        bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
 
        bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
        bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
 }
 
-
-
 /**
  *  fcs_lport_api
  */
@@ -921,13 +909,20 @@ bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
        if (port->fabric) {
                port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
                port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
+               port_attr->authfail =
+                               bfa_fcs_fabric_is_auth_failed(port->fabric);
                port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
                memcpy(port_attr->fabric_ip_addr,
                       bfa_fcs_port_get_fabric_ipaddr(port),
                       BFA_FCS_FABRIC_IPADDR_SZ);
 
-               if (port->vport != NULL)
+               if (port->vport != NULL) {
                        port_attr->port_type = BFA_PPORT_TYPE_VPORT;
+                       port_attr->fpma_mac =
+                               bfa_lps_get_lp_mac(port->vport->lps);
+               } else
+                       port_attr->fpma_mac =
+                               bfa_lps_get_lp_mac(port->fabric->lps);
 
        } else {
                port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
index 9c4b24e..3c27788 100644 (file)
@@ -55,14 +55,7 @@ bfa_fcs_pport_event_handler(void *cbarg, bfa_pport_event_t event)
 }
 
 void
-bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs)
+bfa_fcs_pport_attach(struct bfa_fcs_s *fcs)
 {
-       bfa_pport_event_register(fcs->bfa, bfa_fcs_pport_event_handler,
-                                    fcs);
-}
-
-void
-bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs)
-{
-       bfa_fcs_modexit_comp(fcs);
+       bfa_fcport_event_register(fcs->bfa, bfa_fcs_pport_event_handler, fcs);
 }
index ad01db6..3d57d48 100644 (file)
@@ -93,13 +93,7 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
 }
 
 void
-bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs)
+bfa_fcs_uf_attach(struct bfa_fcs_s *fcs)
 {
        bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
 }
-
-void
-bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs)
-{
-       bfa_fcs_modexit_comp(fcs);
-}
index ede1438..871a4e2 100644 (file)
@@ -53,6 +53,18 @@ bfa_hwcb_reginit(struct bfa_s *bfa)
 }
 
 void
+bfa_hwcb_reqq_ack(struct bfa_s *bfa, int reqq)
+{
+}
+
+static void
+bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
+{
+       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
+               __HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq));
+}
+
+void
 bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
 {
 }
@@ -136,6 +148,7 @@ bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
 void
 bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
 {
+       bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
        bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
 }
 
index 51ae574..76ceb9a 100644 (file)
@@ -85,6 +85,15 @@ bfa_hwct_reginit(struct bfa_s *bfa)
 }
 
 void
+bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq)
+{
+       u32 r32;
+
+       r32 = bfa_reg_read(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
+       bfa_reg_write(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq], r32);
+}
+
+void
 bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
 {
        u32     r32;
index b36540e..0eba3f9 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 #include <bfa.h>
-#include <bfi/bfi_cbreg.h>
+#include <bfi/bfi_ctreg.h>
 #include <bfa_port_priv.h>
 #include <bfa_intr_priv.h>
 #include <cs/bfa_debug.h>
@@ -34,6 +34,26 @@ bfa_msix_lpu(struct bfa_s *bfa)
        bfa_ioc_mbox_isr(&bfa->ioc);
 }
 
+static void
+bfa_reqq_resume(struct bfa_s *bfa, int qid)
+{
+       struct list_head *waitq, *qe, *qen;
+       struct bfa_reqq_wait_s *wqe;
+
+       waitq = bfa_reqq(bfa, qid);
+       list_for_each_safe(qe, qen, waitq) {
+               /**
+                * Callback only as long as there is room in request queue
+                */
+               if (bfa_reqq_full(bfa, qid))
+                       break;
+
+               list_del(qe);
+               wqe = (struct bfa_reqq_wait_s *) qe;
+               wqe->qresume(wqe->cbarg);
+       }
+}
+
 void
 bfa_msix_all(struct bfa_s *bfa, int vec)
 {
@@ -96,7 +116,8 @@ bfa_isr_enable(struct bfa_s *bfa)
 
        bfa_msix_install(bfa);
        intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
-                      __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
+                      __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS |
+                      __HFN_INT_LL_HALT);
 
        if (pci_func == 0)
                intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
@@ -127,23 +148,18 @@ bfa_isr_disable(struct bfa_s *bfa)
 void
 bfa_msix_reqq(struct bfa_s *bfa, int qid)
 {
-       struct list_head                *waitq, *qe, *qen;
-       struct bfa_reqq_wait_s  *wqe;
+       struct list_head *waitq;
 
        qid &= (BFI_IOC_MAX_CQS - 1);
 
-       waitq = bfa_reqq(bfa, qid);
-       list_for_each_safe(qe, qen, waitq) {
-               /**
-                * Callback only as long as there is room in request queue
-                */
-               if (bfa_reqq_full(bfa, qid))
-                       break;
+       bfa->iocfc.hwif.hw_reqq_ack(bfa, qid);
 
-               list_del(qe);
-               wqe = (struct bfa_reqq_wait_s *) qe;
-               wqe->qresume(wqe->cbarg);
-       }
+       /**
+        * Resume any pending requests in the corresponding reqq.
+        */
+       waitq = bfa_reqq(bfa, qid);
+       if (!list_empty(waitq))
+               bfa_reqq_resume(bfa, qid);
 }
 
 void
@@ -157,26 +173,27 @@ bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
 }
 
 void
-bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
+bfa_msix_rspq(struct bfa_s *bfa, int qid)
 {
-       struct bfi_msg_s      *m;
-       u32        pi, ci;
+       struct bfi_msg_s *m;
+       u32 pi, ci;
+       struct list_head *waitq;
 
-       bfa_trc_fp(bfa, rsp_qid);
+       bfa_trc_fp(bfa, qid);
 
-       rsp_qid &= (BFI_IOC_MAX_CQS - 1);
+       qid &= (BFI_IOC_MAX_CQS - 1);
 
-       bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid);
+       bfa->iocfc.hwif.hw_rspq_ack(bfa, qid);
 
-       ci = bfa_rspq_ci(bfa, rsp_qid);
-       pi = bfa_rspq_pi(bfa, rsp_qid);
+       ci = bfa_rspq_ci(bfa, qid);
+       pi = bfa_rspq_pi(bfa, qid);
 
        bfa_trc_fp(bfa, ci);
        bfa_trc_fp(bfa, pi);
 
        if (bfa->rme_process) {
                while (ci != pi) {
-                       m = bfa_rspq_elem(bfa, rsp_qid, ci);
+                       m = bfa_rspq_elem(bfa, qid, ci);
                        bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
 
                        bfa_isrs[m->mhdr.msg_class] (bfa, m);
@@ -188,25 +205,59 @@ bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
        /**
         * update CI
         */
-       bfa_rspq_ci(bfa, rsp_qid) = pi;
-       bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi);
+       bfa_rspq_ci(bfa, qid) = pi;
+       bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi);
        bfa_os_mmiowb();
+
+       /**
+        * Resume any pending requests in the corresponding reqq.
+        */
+       waitq = bfa_reqq(bfa, qid);
+       if (!list_empty(waitq))
+               bfa_reqq_resume(bfa, qid);
 }
 
 void
 bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
 {
-       u32 intr;
+       u32 intr, curr_value;
 
        intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
 
        if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
                bfa_msix_lpu(bfa);
 
-       if (intr & (__HFN_INT_ERR_EMC |
-                   __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 |
-                   __HFN_INT_ERR_PSS))
+       intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
+               __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT);
+
+       if (intr) {
+               if (intr & __HFN_INT_LL_HALT) {
+                       /**
+                        * If LL_HALT bit is set then FW Init Halt LL Port
+                        * Register needs to be cleared as well so Interrupt
+                        * Status Register will be cleared.
+                        */
+                       curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt);
+                       curr_value &= ~__FW_INIT_HALT_P;
+                       bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value);
+               }
+
+               if (intr & __HFN_INT_ERR_PSS) {
+                       /**
+                        * ERR_PSS bit needs to be cleared as well in case
+                        * interrups are shared so driver's interrupt handler is
+                        * still called eventhough it is already masked out.
+                        */
+                       curr_value = bfa_reg_read(
+                               bfa->ioc.ioc_regs.pss_err_status_reg);
+                       curr_value &= __PSS_ERR_STATUS_SET;
+                       bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg,
+                               curr_value);
+               }
+
+               bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr);
                bfa_msix_errint(bfa, intr);
+       }
 }
 
 void
index 397d7e9..e038bc9 100644 (file)
@@ -18,7 +18,7 @@
 #include <bfa.h>
 #include <bfa_ioc.h>
 #include <bfa_fwimg_priv.h>
-#include <bfa_trcmod_priv.h>
+#include <cna/bfa_cna_trcmod.h>
 #include <cs/bfa_debug.h>
 #include <bfi/bfi_ioc.h>
 #include <bfi/bfi_ctreg.h>
 #include <log/bfa_log_hal.h>
 #include <defs/bfa_defs_pci.h>
 
-BFA_TRC_FILE(HAL, IOC);
+BFA_TRC_FILE(CNA, IOC);
 
 /**
  * IOC local definitions
  */
 #define BFA_IOC_TOV            2000    /* msecs */
-#define BFA_IOC_HB_TOV         1000    /* msecs */
-#define BFA_IOC_HB_FAIL_MAX    4
-#define BFA_IOC_HWINIT_MAX     2
+#define BFA_IOC_HWSEM_TOV       500     /* msecs */
+#define BFA_IOC_HB_TOV          500     /* msecs */
+#define BFA_IOC_HWINIT_MAX      2
 #define BFA_IOC_FWIMG_MINSZ     (16 * 1024)
-#define BFA_IOC_TOV_RECOVER    (BFA_IOC_HB_FAIL_MAX * BFA_IOC_HB_TOV \
-                               + BFA_IOC_TOV)
+#define BFA_IOC_TOV_RECOVER      BFA_IOC_HB_TOV
 
 #define bfa_ioc_timer_start(__ioc)                                     \
        bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer,        \
@@ -51,12 +50,25 @@ BFA_TRC_FILE(HAL, IOC);
         (sizeof(struct bfa_trc_mod_s) -                        \
          BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
 #define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
-#define bfa_ioc_stats(_ioc, _stats)    ((_ioc)->stats._stats++)
 
-#define BFA_FLASH_CHUNK_NO(off)         (off / BFI_FLASH_CHUNK_SZ_WORDS)
-#define BFA_FLASH_OFFSET_IN_CHUNK(off)  (off % BFI_FLASH_CHUNK_SZ_WORDS)
-#define BFA_FLASH_CHUNK_ADDR(chunkno)   (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
-bfa_boolean_t   bfa_auto_recover = BFA_FALSE;
+/**
+ * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
+ */
+
+#define bfa_ioc_firmware_lock(__ioc)                    \
+                       ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
+#define bfa_ioc_firmware_unlock(__ioc)                  \
+                       ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
+#define bfa_ioc_fwimg_get_chunk(__ioc, __off)           \
+                       ((__ioc)->ioc_hwif->ioc_fwimg_get_chunk(__ioc, __off))
+#define bfa_ioc_fwimg_get_size(__ioc)                   \
+                       ((__ioc)->ioc_hwif->ioc_fwimg_get_size(__ioc))
+#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
+#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
+#define bfa_ioc_notify_hbfail(__ioc)                    \
+                       ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+
+bfa_boolean_t   bfa_auto_recover = BFA_TRUE;
 
 /*
  * forward declarations
@@ -64,7 +76,6 @@ bfa_boolean_t   bfa_auto_recover = BFA_FALSE;
 static void     bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
                                 enum bfa_ioc_aen_event event);
 static void     bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
-static void     bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
 static void     bfa_ioc_timeout(void *ioc);
@@ -77,8 +88,6 @@ static void     bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
 static void     bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_recover(struct bfa_ioc_s *ioc);
-static bfa_boolean_t bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc);
-static void     bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
 
@@ -508,14 +517,19 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
        bfa_trc(ioc, event);
 
        switch (event) {
-       case IOC_E_HWERROR:
        case IOC_E_FWRSP_DISABLE:
                bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       case IOC_E_HWERROR:
+               bfa_ioc_timer_stop(ioc);
                /*
                 * !!! fall through !!!
                 */
 
        case IOC_E_TIMEOUT:
+               bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
                bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
                break;
 
@@ -608,15 +622,12 @@ bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc)
         * Mark IOC as failed in hardware and stop firmware.
         */
        bfa_ioc_lpu_stop(ioc);
-       bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_HBFAIL);
+       bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
 
-       if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
-               bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
-               /*
-                * Wait for halt to take effect
-                */
-               bfa_reg_read(ioc->ioc_regs.ll_halt);
-       }
+       /**
+        * Notify other functions on HB failure.
+        */
+       bfa_ioc_notify_hbfail(ioc);
 
        /**
         * Notify driver and common modules registered for notification.
@@ -672,6 +683,12 @@ bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event)
                 */
                break;
 
+       case IOC_E_HWERROR:
+               /*
+                * HB failure notification, ignore.
+                */
+               break;
+
        default:
                bfa_sm_fault(ioc, event);
        }
@@ -700,7 +717,7 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
        }
 }
 
-static void
+void
 bfa_ioc_sem_timeout(void *ioc_arg)
 {
        struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg;
@@ -708,26 +725,32 @@ bfa_ioc_sem_timeout(void *ioc_arg)
        bfa_ioc_hw_sem_get(ioc);
 }
 
-static void
-bfa_ioc_usage_sem_get(struct bfa_ioc_s *ioc)
+bfa_boolean_t
+bfa_ioc_sem_get(bfa_os_addr_t sem_reg)
 {
-       u32        r32;
-       int             cnt = 0;
-#define BFA_SEM_SPINCNT        1000
+       u32 r32;
+       int cnt = 0;
+#define BFA_SEM_SPINCNT 3000
 
-       do {
-               r32 = bfa_reg_read(ioc->ioc_regs.ioc_usage_sem_reg);
+       r32 = bfa_reg_read(sem_reg);
+
+       while (r32 && (cnt < BFA_SEM_SPINCNT)) {
                cnt++;
-               if (cnt > BFA_SEM_SPINCNT)
-                       break;
-       } while (r32 != 0);
+               bfa_os_udelay(2);
+               r32 = bfa_reg_read(sem_reg);
+       }
+
+       if (r32 == 0)
+               return BFA_TRUE;
+
        bfa_assert(cnt < BFA_SEM_SPINCNT);
+       return BFA_FALSE;
 }
 
-static void
-bfa_ioc_usage_sem_release(struct bfa_ioc_s *ioc)
+void
+bfa_ioc_sem_release(bfa_os_addr_t sem_reg)
 {
-       bfa_reg_write(ioc->ioc_regs.ioc_usage_sem_reg, 1);
+       bfa_reg_write(sem_reg, 1);
 }
 
 static void
@@ -737,7 +760,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
 
        /**
         * First read to the semaphore register will return 0, subsequent reads
-        * will return 1. Semaphore is released by writing 0 to the register
+        * will return 1. Semaphore is released by writing 1 to the register
         */
        r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
        if (r32 == 0) {
@@ -746,10 +769,10 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
        }
 
        bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout,
-                       ioc, BFA_IOC_TOV);
+                       ioc, BFA_IOC_HWSEM_TOV);
 }
 
-static void
+void
 bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
 {
        bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1);
@@ -828,7 +851,7 @@ bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)
 /**
  * Get driver and firmware versions.
  */
-static void
+void
 bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
 {
        u32        pgnum, pgoff;
@@ -847,24 +870,10 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
        }
 }
 
-static u32 *
-bfa_ioc_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
-{
-       if (ioc->ctdev)
-               return bfi_image_ct_get_chunk(off);
-       return bfi_image_cb_get_chunk(off);
-}
-
-static          u32
-bfa_ioc_fwimg_get_size(struct bfa_ioc_s *ioc)
-{
-return (ioc->ctdev) ? bfi_image_ct_size : bfi_image_cb_size;
-}
-
 /**
  * Returns TRUE if same.
  */
-static          bfa_boolean_t
+bfa_boolean_t
 bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
 {
        struct bfi_ioc_image_hdr_s *drv_fwhdr;
@@ -921,95 +930,6 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc)
 }
 
 /**
- * Return true if firmware of current driver matches the running firmware.
- */
-static          bfa_boolean_t
-bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc)
-{
-       enum bfi_ioc_state ioc_fwstate;
-       u32        usecnt;
-       struct bfi_ioc_image_hdr_s fwhdr;
-
-       /**
-        * Firmware match check is relevant only for CNA.
-        */
-       if (!ioc->cna)
-               return BFA_TRUE;
-
-       /**
-        * If bios boot (flash based) -- do not increment usage count
-        */
-       if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
-               return BFA_TRUE;
-
-       bfa_ioc_usage_sem_get(ioc);
-       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
-
-       /**
-        * If usage count is 0, always return TRUE.
-        */
-       if (usecnt == 0) {
-               bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
-               bfa_ioc_usage_sem_release(ioc);
-               bfa_trc(ioc, usecnt);
-               return BFA_TRUE;
-       }
-
-       ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
-       bfa_trc(ioc, ioc_fwstate);
-
-       /**
-        * Use count cannot be non-zero and chip in uninitialized state.
-        */
-       bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
-
-       /**
-        * Check if another driver with a different firmware is active
-        */
-       bfa_ioc_fwver_get(ioc, &fwhdr);
-       if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
-               bfa_ioc_usage_sem_release(ioc);
-               bfa_trc(ioc, usecnt);
-               return BFA_FALSE;
-       }
-
-       /**
-        * Same firmware version. Increment the reference count.
-        */
-       usecnt++;
-       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
-       bfa_ioc_usage_sem_release(ioc);
-       bfa_trc(ioc, usecnt);
-       return BFA_TRUE;
-}
-
-static void
-bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc)
-{
-       u32        usecnt;
-
-       /**
-        * Firmware lock is relevant only for CNA.
-        * If bios boot (flash based) -- do not decrement usage count
-        */
-       if (!ioc->cna || (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ))
-               return;
-
-       /**
-        * decrement usage count
-        */
-       bfa_ioc_usage_sem_get(ioc);
-       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
-       bfa_assert(usecnt > 0);
-
-       usecnt--;
-       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
-       bfa_trc(ioc, usecnt);
-
-       bfa_ioc_usage_sem_release(ioc);
-}
-
-/**
  * Conditionally flush any pending message from firmware at start.
  */
 static void
@@ -1152,33 +1072,27 @@ bfa_ioc_send_getattr(struct bfa_ioc_s *ioc)
 static void
 bfa_ioc_hb_check(void *cbarg)
 {
-       struct bfa_ioc_s *ioc = cbarg;
-       u32        hb_count;
+       struct bfa_ioc_s  *ioc = cbarg;
+       u32     hb_count;
 
        hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
        if (ioc->hb_count == hb_count) {
-               ioc->hb_fail++;
-       } else {
-               ioc->hb_count = hb_count;
-               ioc->hb_fail = 0;
-       }
-
-       if (ioc->hb_fail >= BFA_IOC_HB_FAIL_MAX) {
-               bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE, hb_count);
-               ioc->hb_fail = 0;
+               bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE,
+                       hb_count);
                bfa_ioc_recover(ioc);
                return;
+       } else {
+               ioc->hb_count = hb_count;
        }
 
        bfa_ioc_mbox_poll(ioc);
-       bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
-                       BFA_IOC_HB_TOV);
+       bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check,
+                       ioc, BFA_IOC_HB_TOV);
 }
 
 static void
 bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
 {
-       ioc->hb_fail = 0;
        ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
        bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
                        BFA_IOC_HB_TOV);
@@ -1191,112 +1105,6 @@ bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
 }
 
 /**
- * Host to LPU mailbox message addresses
- */
-static struct {
-       u32        hfn_mbox, lpu_mbox, hfn_pgn;
-} iocreg_fnreg[] = {
-       {
-       HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0}, {
-       HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1}, {
-       HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2}, {
-       HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3}
-};
-
-/**
- * Host <-> LPU mailbox command/status registers - port 0
- */
-static struct {
-       u32        hfn, lpu;
-} iocreg_mbcmd_p0[] = {
-       {
-       HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT}, {
-       HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT}, {
-       HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT}, {
-       HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT}
-};
-
-/**
- * Host <-> LPU mailbox command/status registers - port 1
- */
-static struct {
-       u32        hfn, lpu;
-} iocreg_mbcmd_p1[] = {
-       {
-       HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT}, {
-       HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT}, {
-       HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT}, {
-       HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT}
-};
-
-/**
- * Shared IRQ handling in INTX mode
- */
-static struct {
-       u32        isr, msk;
-} iocreg_shirq_next[] = {
-       {
-       HOSTFN1_INT_STATUS, HOSTFN1_INT_MSK}, {
-       HOSTFN2_INT_STATUS, HOSTFN2_INT_MSK}, {
-       HOSTFN3_INT_STATUS, HOSTFN3_INT_MSK}, {
-HOSTFN0_INT_STATUS, HOSTFN0_INT_MSK},};
-
-static void
-bfa_ioc_reg_init(struct bfa_ioc_s *ioc)
-{
-       bfa_os_addr_t   rb;
-       int             pcifn = bfa_ioc_pcifn(ioc);
-
-       rb = bfa_ioc_bar0(ioc);
-
-       ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
-       ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
-       ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
-
-       if (ioc->port_id == 0) {
-               ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
-               ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
-               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
-               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
-               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
-       } else {
-               ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
-               ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
-               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
-               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
-               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
-       }
-
-       /**
-        * Shared IRQ handling in INTX mode
-        */
-       ioc->ioc_regs.shirq_isr_next = rb + iocreg_shirq_next[pcifn].isr;
-       ioc->ioc_regs.shirq_msk_next = rb + iocreg_shirq_next[pcifn].msk;
-
-       /*
-        * PSS control registers
-        */
-       ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
-       ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
-       ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
-
-       /*
-        * IOC semaphore registers and serialization
-        */
-       ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
-       ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
-       ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
-
-       /**
-        * sram memory access
-        */
-       ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
-       ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
-       if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT)
-               ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
-}
-
-/**
  *      Initiate a full firmware download.
  */
 static void
@@ -1321,9 +1129,6 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
        if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
                boot_type = BFI_BOOT_TYPE_FLASH;
        fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
-       fwimg[BFI_BOOT_TYPE_OFF / sizeof(u32)] = bfa_os_swap32(boot_type);
-       fwimg[BFI_BOOT_PARAM_OFF / sizeof(u32)] =
-               bfa_os_swap32(boot_param);
 
        pgnum = bfa_ioc_smem_pgnum(ioc, loff);
        pgoff = bfa_ioc_smem_pgoff(ioc, loff);
@@ -1332,17 +1137,17 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
 
        for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
 
-               if (BFA_FLASH_CHUNK_NO(i) != chunkno) {
-                       chunkno = BFA_FLASH_CHUNK_NO(i);
+               if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
+                       chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
                        fwimg = bfa_ioc_fwimg_get_chunk(ioc,
-                                       BFA_FLASH_CHUNK_ADDR(chunkno));
+                                       BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
                }
 
                /**
                 * write smem
                 */
                bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
-                             fwimg[BFA_FLASH_OFFSET_IN_CHUNK(i)]);
+                             fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]);
 
                loff += sizeof(u32);
 
@@ -1358,6 +1163,14 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
 
        bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
                      bfa_ioc_smem_pgnum(ioc, 0));
+
+       /*
+        * Set boot type and boot param at the end.
+        */
+       bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF,
+                       bfa_os_swap32(boot_type));
+       bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_PARAM_OFF,
+                       bfa_os_swap32(boot_param));
 }
 
 static void
@@ -1440,168 +1253,10 @@ bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
 }
 
 /**
- * Initialize IOC to port mapping.
- */
-
-#define FNC_PERS_FN_SHIFT(__fn)        ((__fn) * 8)
-static void
-bfa_ioc_map_port(struct bfa_ioc_s *ioc)
-{
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
-       u32        r32;
-
-       /**
-        * For crossbow, port id is same as pci function.
-        */
-       if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT) {
-               ioc->port_id = bfa_ioc_pcifn(ioc);
-               return;
-       }
-
-       /**
-        * For catapult, base port id on personality register and IOC type
-        */
-       r32 = bfa_reg_read(rb + FNC_PERS_REG);
-       r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
-       ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
-
-       bfa_trc(ioc, bfa_ioc_pcifn(ioc));
-       bfa_trc(ioc, ioc->port_id);
-}
-
-
-
-/**
  *  bfa_ioc_public
  */
 
 /**
-* Set interrupt mode for a function: INTX or MSIX
- */
-void
-bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
-{
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
-       u32        r32, mode;
-
-       r32 = bfa_reg_read(rb + FNC_PERS_REG);
-       bfa_trc(ioc, r32);
-
-       mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
-               __F0_INTX_STATUS;
-
-       /**
-        * If already in desired mode, do not change anything
-        */
-       if (!msix && mode)
-               return;
-
-       if (msix)
-               mode = __F0_INTX_STATUS_MSIX;
-       else
-               mode = __F0_INTX_STATUS_INTA;
-
-       r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
-       r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
-       bfa_trc(ioc, r32);
-
-       bfa_reg_write(rb + FNC_PERS_REG, r32);
-}
-
-bfa_status_t
-bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
-{
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
-       u32        pll_sclk, pll_fclk, r32;
-
-       if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
-               pll_sclk =
-                       __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
-                       __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) |
-                       __APP_PLL_312_JITLMT0_1(3U) |
-                       __APP_PLL_312_CNTLMT0_1(1U);
-               pll_fclk =
-                       __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
-                       __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) |
-                       __APP_PLL_425_JITLMT0_1(3U) |
-                       __APP_PLL_425_CNTLMT0_1(1U);
-
-               /**
-                *      For catapult, choose operational mode FC/FCoE
-                */
-               if (ioc->fcmode) {
-                       bfa_reg_write((rb + OP_MODE), 0);
-                       bfa_reg_write((rb + ETH_MAC_SER_REG),
-                                     __APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2
-                                     | __APP_EMS_CHANNEL_SEL);
-               } else {
-                       ioc->pllinit = BFA_TRUE;
-                       bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
-                       bfa_reg_write((rb + ETH_MAC_SER_REG),
-                                     __APP_EMS_REFCKBUFEN1);
-               }
-       } else {
-               pll_sclk =
-                       __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
-                       __APP_PLL_312_P0_1(3U) | __APP_PLL_312_JITLMT0_1(3U) |
-                       __APP_PLL_312_CNTLMT0_1(3U);
-               pll_fclk =
-                       __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
-                       __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
-                       __APP_PLL_425_JITLMT0_1(3U) |
-                       __APP_PLL_425_CNTLMT0_1(3U);
-       }
-
-       bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
-       bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
-
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-
-       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
-                     __APP_PLL_312_LOGIC_SOFT_RESET);
-       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
-                     __APP_PLL_312_BYPASS | __APP_PLL_312_LOGIC_SOFT_RESET);
-       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
-                     __APP_PLL_425_LOGIC_SOFT_RESET);
-       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
-                     __APP_PLL_425_BYPASS | __APP_PLL_425_LOGIC_SOFT_RESET);
-       bfa_os_udelay(2);
-       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
-                     __APP_PLL_312_LOGIC_SOFT_RESET);
-       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
-                     __APP_PLL_425_LOGIC_SOFT_RESET);
-
-       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
-                     pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET);
-       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
-                     pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET);
-
-       /**
-        * Wait for PLLs to lock.
-        */
-       bfa_os_udelay(2000);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-
-       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
-       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
-
-       if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
-               bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
-               bfa_os_udelay(1000);
-               r32 = bfa_reg_read((rb + MBIST_STAT_REG));
-               bfa_trc(ioc, r32);
-       }
-
-       return BFA_STATUS_OK;
-}
-
-/**
  * Interface used by diag module to do firmware boot with memory test
  * as the entry vector.
  */
@@ -1642,7 +1297,7 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param)
 void
 bfa_ioc_auto_recover(bfa_boolean_t auto_recover)
 {
-       bfa_auto_recover = BFA_FALSE;
+       bfa_auto_recover = auto_recover;
 }
 
 
@@ -1764,6 +1419,14 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
        ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
        ioc->cna = ioc->ctdev && !ioc->fcmode;
 
+       /**
+        * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c
+        */
+       if (ioc->ctdev)
+               bfa_ioc_set_ct_hwif(ioc);
+       else
+               bfa_ioc_set_cb_hwif(ioc);
+
        bfa_ioc_map_port(ioc);
        bfa_ioc_reg_init(ioc);
 }
@@ -1830,7 +1493,6 @@ return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
 void
 bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
 {
-       bfa_assert(ioc->auto_recover);
        ioc->dbg_fwsave = dbg_fwsave;
        ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover);
 }
@@ -1973,7 +1635,7 @@ bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
         ((__sm) == BFI_IOC_INITING) ||         \
         ((__sm) == BFI_IOC_HWINIT) ||          \
         ((__sm) == BFI_IOC_DISABLED) ||        \
-        ((__sm) == BFI_IOC_HBFAIL) ||          \
+        ((__sm) == BFI_IOC_FAIL) ||            \
         ((__sm) == BFI_IOC_CFG_DISABLED))
 
 /**
@@ -2017,46 +1679,28 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
                         struct bfa_adapter_attr_s *ad_attr)
 {
        struct bfi_ioc_attr_s *ioc_attr;
-       char            model[BFA_ADAPTER_MODEL_NAME_LEN];
 
        ioc_attr = ioc->attr;
-       bfa_os_memcpy((void *)&ad_attr->serial_num,
-                     (void *)ioc_attr->brcd_serialnum,
-                     BFA_ADAPTER_SERIAL_NUM_LEN);
-
-       bfa_os_memcpy(&ad_attr->fw_ver, ioc_attr->fw_version, BFA_VERSION_LEN);
-       bfa_os_memcpy(&ad_attr->optrom_ver, ioc_attr->optrom_version,
-                     BFA_VERSION_LEN);
-       bfa_os_memcpy(&ad_attr->manufacturer, BFA_MFG_NAME,
-                     BFA_ADAPTER_MFG_NAME_LEN);
+
+       bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
+       bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
+       bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
+       bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
        bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
                      sizeof(struct bfa_mfg_vpd_s));
 
-       ad_attr->nports = BFI_ADAPTER_GETP(NPORTS, ioc_attr->adapter_prop);
-       ad_attr->max_speed = BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
+       ad_attr->nports = bfa_ioc_get_nports(ioc);
+       ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
 
-       /**
-        * model name
-        */
-       if (BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop) == 10) {
-               strcpy(model, "BR-10?0");
-               model[5] = '0' + ad_attr->nports;
-       } else {
-               strcpy(model, "Brocade-??5");
-               model[8] =
-                       '0' + BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
-               model[9] = '0' + ad_attr->nports;
-       }
+       bfa_ioc_get_adapter_model(ioc, ad_attr->model);
+       /* For now, model descr uses same model string */
+       bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
 
        if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
                ad_attr->prototype = 1;
        else
                ad_attr->prototype = 0;
 
-       bfa_os_memcpy(&ad_attr->model, model, BFA_ADAPTER_MODEL_NAME_LEN);
-       bfa_os_memcpy(&ad_attr->model_descr, &ad_attr->model,
-                     BFA_ADAPTER_MODEL_NAME_LEN);
-
        ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
        ad_attr->mac = bfa_ioc_get_mac(ioc);
 
@@ -2064,41 +1708,122 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
        ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
        ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
        ad_attr->asic_rev = ioc_attr->asic_rev;
-       ad_attr->hw_ver[0] = 'R';
-       ad_attr->hw_ver[1] = 'e';
-       ad_attr->hw_ver[2] = 'v';
-       ad_attr->hw_ver[3] = '-';
-       ad_attr->hw_ver[4] = ioc_attr->asic_rev;
-       ad_attr->hw_ver[5] = '\0';
+
+       bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
 
        ad_attr->cna_capable = ioc->cna;
 }
 
+enum bfa_ioc_type_e
+bfa_ioc_get_type(struct bfa_ioc_s *ioc)
+{
+       if (!ioc->ctdev || ioc->fcmode)
+               return BFA_IOC_TYPE_FC;
+       else if (ioc->ioc_mc == BFI_MC_IOCFC)
+               return BFA_IOC_TYPE_FCoE;
+       else if (ioc->ioc_mc == BFI_MC_LL)
+               return BFA_IOC_TYPE_LL;
+       else {
+               bfa_assert(ioc->ioc_mc == BFI_MC_LL);
+               return BFA_IOC_TYPE_LL;
+       }
+}
+
+void
+bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)
+{
+       bfa_os_memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+       bfa_os_memcpy((void *)serial_num,
+                       (void *)ioc->attr->brcd_serialnum,
+                       BFA_ADAPTER_SERIAL_NUM_LEN);
+}
+
+void
+bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver)
+{
+       bfa_os_memset((void *)fw_ver, 0, BFA_VERSION_LEN);
+       bfa_os_memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+}
+
+void
+bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)
+{
+       bfa_assert(chip_rev);
+
+       bfa_os_memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+
+       chip_rev[0] = 'R';
+       chip_rev[1] = 'e';
+       chip_rev[2] = 'v';
+       chip_rev[3] = '-';
+       chip_rev[4] = ioc->attr->asic_rev;
+       chip_rev[5] = '\0';
+}
+
+void
+bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver)
+{
+       bfa_os_memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
+       bfa_os_memcpy(optrom_ver, ioc->attr->optrom_version,
+               BFA_VERSION_LEN);
+}
+
+void
+bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
+{
+       bfa_os_memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+       bfa_os_memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+}
+
+void
+bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)
+{
+       struct bfi_ioc_attr_s   *ioc_attr;
+       u8              nports;
+       u8              max_speed;
+
+       bfa_assert(model);
+       bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+
+       ioc_attr = ioc->attr;
+
+       nports = bfa_ioc_get_nports(ioc);
+       max_speed = bfa_ioc_speed_sup(ioc);
+
+       /**
+        * model name
+        */
+       if (max_speed == 10) {
+               strcpy(model, "BR-10?0");
+               model[5] = '0' + nports;
+       } else {
+               strcpy(model, "Brocade-??5");
+               model[8] = '0' + max_speed;
+               model[9] = '0' + nports;
+       }
+}
+
+enum bfa_ioc_state
+bfa_ioc_get_state(struct bfa_ioc_s *ioc)
+{
+       return bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+}
+
 void
 bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
 {
        bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
 
-       ioc_attr->state = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+       ioc_attr->state = bfa_ioc_get_state(ioc);
        ioc_attr->port_id = ioc->port_id;
 
-       if (!ioc->ctdev)
-               ioc_attr->ioc_type = BFA_IOC_TYPE_FC;
-       else if (ioc->ioc_mc == BFI_MC_IOCFC)
-               ioc_attr->ioc_type = BFA_IOC_TYPE_FCoE;
-       else if (ioc->ioc_mc == BFI_MC_LL)
-               ioc_attr->ioc_type = BFA_IOC_TYPE_LL;
+       ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
 
        bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
 
        ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
        ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
-       ioc_attr->pci_attr.chip_rev[0] = 'R';
-       ioc_attr->pci_attr.chip_rev[1] = 'e';
-       ioc_attr->pci_attr.chip_rev[2] = 'v';
-       ioc_attr->pci_attr.chip_rev[3] = '-';
-       ioc_attr->pci_attr.chip_rev[4] = ioc_attr->adapter_attr.asic_rev;
-       ioc_attr->pci_attr.chip_rev[5] = '\0';
+       bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
 }
 
 /**
@@ -2195,29 +1920,6 @@ bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
 }
 
 /**
- * Return true if interrupt should be claimed.
- */
-bfa_boolean_t
-bfa_ioc_intx_claim(struct bfa_ioc_s *ioc)
-{
-       u32        isr, msk;
-
-       /**
-        * Always claim if not catapult.
-        */
-       if (!ioc->ctdev)
-               return BFA_TRUE;
-
-       /**
-        * FALSE if next device is claiming interrupt.
-        * TRUE if next device is not interrupting or not present.
-        */
-       msk = bfa_reg_read(ioc->ioc_regs.shirq_msk_next);
-       isr = bfa_reg_read(ioc->ioc_regs.shirq_isr_next);
-       return !(isr & ~msk);
-}
-
-/**
  * Send AEN notification
  */
 static void
@@ -2226,32 +1928,14 @@ bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
        union bfa_aen_data_u aen_data;
        struct bfa_log_mod_s *logmod = ioc->logm;
        s32         inst_num = 0;
-       struct bfa_ioc_attr_s ioc_attr;
+       enum bfa_ioc_type_e ioc_type;
 
-       switch (event) {
-       case BFA_IOC_AEN_HBGOOD:
-               bfa_log(logmod, BFA_AEN_IOC_HBGOOD, inst_num);
-               break;
-       case BFA_IOC_AEN_HBFAIL:
-               bfa_log(logmod, BFA_AEN_IOC_HBFAIL, inst_num);
-               break;
-       case BFA_IOC_AEN_ENABLE:
-               bfa_log(logmod, BFA_AEN_IOC_ENABLE, inst_num);
-               break;
-       case BFA_IOC_AEN_DISABLE:
-               bfa_log(logmod, BFA_AEN_IOC_DISABLE, inst_num);
-               break;
-       case BFA_IOC_AEN_FWMISMATCH:
-               bfa_log(logmod, BFA_AEN_IOC_FWMISMATCH, inst_num);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, event), inst_num);
 
        memset(&aen_data.ioc.pwwn, 0, sizeof(aen_data.ioc.pwwn));
        memset(&aen_data.ioc.mac, 0, sizeof(aen_data.ioc.mac));
-       bfa_ioc_get_attr(ioc, &ioc_attr);
-       switch (ioc_attr.ioc_type) {
+       ioc_type = bfa_ioc_get_type(ioc);
+       switch (ioc_type) {
        case BFA_IOC_TYPE_FC:
                aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
                break;
@@ -2263,10 +1947,10 @@ bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
                aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
                break;
        default:
-               bfa_assert(ioc_attr.ioc_type == BFA_IOC_TYPE_FC);
+               bfa_assert(ioc_type == BFA_IOC_TYPE_FC);
                break;
        }
-       aen_data.ioc.ioc_type = ioc_attr.ioc_type;
+       aen_data.ioc.ioc_type = ioc_type;
 }
 
 /**
@@ -2290,6 +1974,15 @@ bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
 }
 
 /**
+ * Clear saved firmware trace
+ */
+void
+bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc)
+{
+       ioc->dbg_fwsave_once = BFA_TRUE;
+}
+
+/**
  * Retrieve saved firmware trace from a prior IOC failure.
  */
 bfa_status_t
@@ -2304,6 +1997,13 @@ bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
 
        pgnum = bfa_ioc_smem_pgnum(ioc, loff);
        loff = bfa_ioc_smem_pgoff(ioc, loff);
+
+       /*
+        *  Hold semaphore to serialize pll init and fwtrc.
+        */
+       if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg))
+               return BFA_STATUS_FAILED;
+
        bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
 
        tlen = *trclen;
@@ -2329,6 +2029,12 @@ bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
        }
        bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
                      bfa_ioc_smem_pgnum(ioc, 0));
+
+       /*
+        *  release semaphore.
+        */
+       bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
        bfa_trc(ioc, pgnum);
 
        *trclen = tlen * sizeof(u32);
index 7c30f05..d080440 100644 (file)
@@ -74,15 +74,18 @@ struct bfa_ioc_regs_s {
        bfa_os_addr_t   lpu_mbox_cmd;
        bfa_os_addr_t   lpu_mbox;
        bfa_os_addr_t   pss_ctl_reg;
+       bfa_os_addr_t   pss_err_status_reg;
        bfa_os_addr_t   app_pll_fast_ctl_reg;
        bfa_os_addr_t   app_pll_slow_ctl_reg;
        bfa_os_addr_t   ioc_sem_reg;
        bfa_os_addr_t   ioc_usage_sem_reg;
+       bfa_os_addr_t   ioc_init_sem_reg;
        bfa_os_addr_t   ioc_usage_reg;
        bfa_os_addr_t   host_page_num_fn;
        bfa_os_addr_t   heartbeat;
        bfa_os_addr_t   ioc_fwstate;
        bfa_os_addr_t   ll_halt;
+       bfa_os_addr_t   err_set;
        bfa_os_addr_t   shirq_isr_next;
        bfa_os_addr_t   shirq_msk_next;
        bfa_os_addr_t   smem_page_start;
@@ -154,7 +157,6 @@ struct bfa_ioc_s {
        struct bfa_timer_s      ioc_timer;
        struct bfa_timer_s      sem_timer;
        u32             hb_count;
-       u32             hb_fail;
        u32             retry_count;
        struct list_head                hb_notify_q;
        void                    *dbg_fwsave;
@@ -177,6 +179,22 @@ struct bfa_ioc_s {
        struct bfi_ioc_attr_s   *attr;
        struct bfa_ioc_cbfn_s   *cbfn;
        struct bfa_ioc_mbox_mod_s mbox_mod;
+       struct bfa_ioc_hwif_s   *ioc_hwif;
+};
+
+struct bfa_ioc_hwif_s {
+       bfa_status_t    (*ioc_pll_init) (struct bfa_ioc_s *ioc);
+       bfa_boolean_t   (*ioc_firmware_lock)    (struct bfa_ioc_s *ioc);
+       void            (*ioc_firmware_unlock)  (struct bfa_ioc_s *ioc);
+       u32 *           (*ioc_fwimg_get_chunk)  (struct bfa_ioc_s *ioc,
+                                               u32 off);
+       u32             (*ioc_fwimg_get_size)   (struct bfa_ioc_s *ioc);
+       void            (*ioc_reg_init) (struct bfa_ioc_s *ioc);
+       void            (*ioc_map_port) (struct bfa_ioc_s *ioc);
+       void            (*ioc_isr_mode_set)     (struct bfa_ioc_s *ioc,
+                                               bfa_boolean_t msix);
+       void            (*ioc_notify_hbfail)    (struct bfa_ioc_s *ioc);
+       void            (*ioc_ownership_reset)  (struct bfa_ioc_s *ioc);
 };
 
 #define bfa_ioc_pcifn(__ioc)           ((__ioc)->pcidev.pci_func)
@@ -191,6 +209,15 @@ struct bfa_ioc_s {
 #define bfa_ioc_rx_bbcredit(__ioc)     ((__ioc)->attr->rx_bbcredit)
 #define bfa_ioc_speed_sup(__ioc)       \
        BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
+#define bfa_ioc_get_nports(__ioc)       \
+       BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop)
+
+#define bfa_ioc_stats(_ioc, _stats)     ((_ioc)->stats._stats++)
+#define BFA_IOC_FWIMG_MINSZ     (16 * 1024)
+
+#define BFA_IOC_FLASH_CHUNK_NO(off)             (off / BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off)      (off % BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno)  (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
 
 /**
  * IOC mailbox interface
@@ -207,6 +234,14 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
 /**
  * IOC interfaces
  */
+#define bfa_ioc_pll_init(__ioc) ((__ioc)->ioc_hwif->ioc_pll_init(__ioc))
+#define bfa_ioc_isr_mode_set(__ioc, __msix)                     \
+                       ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
+#define bfa_ioc_ownership_reset(__ioc)                          \
+                       ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc))
+
+void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc);
+void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc);
 void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa,
                struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod,
                struct bfa_trc_mod_s *trcmod,
@@ -223,13 +258,21 @@ bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc);
 void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param);
 void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg);
 void bfa_ioc_error_isr(struct bfa_ioc_s *ioc);
-void bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t intx);
-bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
 void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc);
+enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc);
+void bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num);
+void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver);
+void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver);
+void bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model);
+void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc,
+       char *manufacturer);
+void bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev);
+enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc);
+
 void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
 void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
                struct bfa_adapter_attr_s *ad_attr);
@@ -237,6 +280,7 @@ int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
 void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
 bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
                int *trclen);
+void bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc);
 bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
                                 int *trclen);
 u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
@@ -245,6 +289,13 @@ void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
 void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
        struct bfa_ioc_hbfail_notify_s *notify);
+bfa_boolean_t bfa_ioc_sem_get(bfa_os_addr_t sem_reg);
+void bfa_ioc_sem_release(bfa_os_addr_t sem_reg);
+void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
+void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
+                       struct bfi_ioc_image_hdr_s *fwhdr);
+bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
+                       struct bfi_ioc_image_hdr_s *fwhdr);
 
 /*
  * bfa mfg wwn API functions
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
new file mode 100644 (file)
index 0000000..3ce8531
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) 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.
+ */
+
+#include <bfa.h>
+#include <bfa_ioc.h>
+#include <bfa_fwimg_priv.h>
+#include <cna/bfa_cna_trcmod.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_cbreg.h>
+#include <log/bfa_log_hal.h>
+#include <defs/bfa_defs_pci.h>
+
+BFA_TRC_FILE(CNA, IOC_CB);
+
+/*
+ * forward declarations
+ */
+static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
+static u32  *bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off);
+static u32 bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
+static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
+
+struct bfa_ioc_hwif_s hwif_cb = {
+       bfa_ioc_cb_pll_init,
+       bfa_ioc_cb_firmware_lock,
+       bfa_ioc_cb_firmware_unlock,
+       bfa_ioc_cb_fwimg_get_chunk,
+       bfa_ioc_cb_fwimg_get_size,
+       bfa_ioc_cb_reg_init,
+       bfa_ioc_cb_map_port,
+       bfa_ioc_cb_isr_mode_set,
+       bfa_ioc_cb_notify_hbfail,
+       bfa_ioc_cb_ownership_reset,
+};
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
+{
+       ioc->ioc_hwif = &hwif_cb;
+}
+
+static u32 *
+bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
+{
+       return bfi_image_cb_get_chunk(off);
+}
+
+static u32
+bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc)
+{
+       return bfi_image_cb_size;
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bfa_boolean_t
+bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
+{
+       return BFA_TRUE;
+}
+
+static void
+bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc)
+{
+}
+
+/**
+ * Notify other functions on HB failure.
+ */
+static void
+bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc)
+{
+       bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
+       bfa_reg_read(ioc->ioc_regs.err_set);
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
+       { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
+       { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
+       { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT },
+       { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT }
+};
+
+static void
+bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
+{
+       bfa_os_addr_t   rb;
+       int             pcifn = bfa_ioc_pcifn(ioc);
+
+       rb = bfa_ioc_bar0(ioc);
+
+       ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+       ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+       ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+       if (ioc->port_id == 0) {
+               ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+               ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+       } else {
+               ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+               ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+       }
+
+       /**
+        * Host <-> LPU mailbox command/status registers
+        */
+       ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn;
+       ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd[pcifn].lpu;
+
+       /*
+        * PSS control registers
+        */
+       ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+       ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
+       ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_400_CTL_REG);
+       ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_212_CTL_REG);
+
+       /*
+        * IOC semaphore registers and serialization
+        */
+       ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+       ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
+
+       /**
+        * sram memory access
+        */
+       ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+       ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
+
+       /*
+        * err set reg : for notification of hb failure
+        */
+       ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+static void
+bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
+{
+       /**
+        * For crossbow, port id is same as pci function.
+        */
+       ioc->port_id = bfa_ioc_pcifn(ioc);
+       bfa_trc(ioc, ioc->port_id);
+}
+
+/**
+ * Set interrupt mode for a function: INTX or MSIX
+ */
+static void
+bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
+{
+}
+
+static bfa_status_t
+bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc)
+{
+       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       u32     pll_sclk, pll_fclk;
+
+       /*
+        *  Hold semaphore so that nobody can access the chip during init.
+        */
+       bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
+
+       pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN |
+                       __APP_PLL_212_P0_1(3U) |
+                       __APP_PLL_212_JITLMT0_1(3U) |
+                       __APP_PLL_212_CNTLMT0_1(3U);
+       pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN |
+                       __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) |
+                       __APP_PLL_400_JITLMT0_1(3U) |
+                       __APP_PLL_400_CNTLMT0_1(3U);
+
+       bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
+       bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
+
+       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+                       __APP_PLL_212_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+                       __APP_PLL_212_BYPASS |
+                       __APP_PLL_212_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+                       __APP_PLL_400_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+                       __APP_PLL_400_BYPASS |
+                       __APP_PLL_400_LOGIC_SOFT_RESET);
+       bfa_os_udelay(2);
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+                       __APP_PLL_212_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+                       __APP_PLL_400_LOGIC_SOFT_RESET);
+
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+                       pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+                       pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET);
+
+       /**
+        * Wait for PLLs to lock.
+        */
+       bfa_os_udelay(2000);
+       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
+
+       /*
+        *  release semaphore.
+        */
+       bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+       return BFA_STATUS_OK;
+}
+
+/**
+ * Cleanup hw semaphore and usecnt registers
+ */
+static void
+bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc)
+{
+
+       /*
+        * Read the hw sem reg to make sure that it is locked
+        * before we clear it. If it is not locked, writing 1
+        * will lock it instead of clearing it.
+        */
+       bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+       bfa_ioc_hw_sem_release(ioc);
+}
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
new file mode 100644 (file)
index 0000000..20b58ad
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) 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.
+ */
+
+#include <bfa.h>
+#include <bfa_ioc.h>
+#include <bfa_fwimg_priv.h>
+#include <cna/bfa_cna_trcmod.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_ctreg.h>
+#include <log/bfa_log_hal.h>
+#include <defs/bfa_defs_pci.h>
+
+BFA_TRC_FILE(CNA, IOC_CT);
+
+/*
+ * forward declarations
+ */
+static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc);
+static u32* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc,
+                                       u32 off);
+static u32 bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
+static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
+
+struct bfa_ioc_hwif_s hwif_ct = {
+       bfa_ioc_ct_pll_init,
+       bfa_ioc_ct_firmware_lock,
+       bfa_ioc_ct_firmware_unlock,
+       bfa_ioc_ct_fwimg_get_chunk,
+       bfa_ioc_ct_fwimg_get_size,
+       bfa_ioc_ct_reg_init,
+       bfa_ioc_ct_map_port,
+       bfa_ioc_ct_isr_mode_set,
+       bfa_ioc_ct_notify_hbfail,
+       bfa_ioc_ct_ownership_reset,
+};
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
+{
+       ioc->ioc_hwif = &hwif_ct;
+}
+
+static u32*
+bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
+{
+       return bfi_image_ct_get_chunk(off);
+}
+
+static u32
+bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc)
+{
+       return bfi_image_ct_size;
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bfa_boolean_t
+bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
+{
+       enum bfi_ioc_state ioc_fwstate;
+       u32 usecnt;
+       struct bfi_ioc_image_hdr_s fwhdr;
+
+       /**
+        * Firmware match check is relevant only for CNA.
+        */
+       if (!ioc->cna)
+               return BFA_TRUE;
+
+       /**
+        * If bios boot (flash based) -- do not increment usage count
+        */
+       if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+               return BFA_TRUE;
+
+       bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+
+       /**
+        * If usage count is 0, always return TRUE.
+        */
+       if (usecnt == 0) {
+               bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
+               bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+               bfa_trc(ioc, usecnt);
+               return BFA_TRUE;
+       }
+
+       ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+       bfa_trc(ioc, ioc_fwstate);
+
+       /**
+        * Use count cannot be non-zero and chip in uninitialized state.
+        */
+       bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
+
+       /**
+        * Check if another driver with a different firmware is active
+        */
+       bfa_ioc_fwver_get(ioc, &fwhdr);
+       if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
+               bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+               bfa_trc(ioc, usecnt);
+               return BFA_FALSE;
+       }
+
+       /**
+        * Same firmware version. Increment the reference count.
+        */
+       usecnt++;
+       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+       bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+       bfa_trc(ioc, usecnt);
+       return BFA_TRUE;
+}
+
+static void
+bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
+{
+       u32 usecnt;
+
+       /**
+        * Firmware lock is relevant only for CNA.
+        * If bios boot (flash based) -- do not decrement usage count
+        */
+       if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+               return;
+
+       /**
+        * decrement usage count
+        */
+       bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+       bfa_assert(usecnt > 0);
+
+       usecnt--;
+       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+       bfa_trc(ioc, usecnt);
+
+       bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+}
+
+/**
+ * Notify other functions on HB failure.
+ */
+static void
+bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc)
+{
+       if (ioc->cna) {
+               bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
+               /* Wait for halt to take effect */
+               bfa_reg_read(ioc->ioc_regs.ll_halt);
+       } else {
+               bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
+               bfa_reg_read(ioc->ioc_regs.err_set);
+       }
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
+       { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
+       { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
+       { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
+       { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
+       { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT },
+       { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT },
+       { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT },
+       { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
+       { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT },
+       { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT },
+       { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT },
+       { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+static void
+bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
+{
+       bfa_os_addr_t   rb;
+       int             pcifn = bfa_ioc_pcifn(ioc);
+
+       rb = bfa_ioc_bar0(ioc);
+
+       ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+       ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+       ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+       if (ioc->port_id == 0) {
+               ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+               ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
+               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
+               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+       } else {
+               ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+               ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
+               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
+               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+       }
+
+       /*
+        * PSS control registers
+        */
+       ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+       ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
+       ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
+       ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
+
+       /*
+        * IOC semaphore registers and serialization
+        */
+       ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+       ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
+       ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
+       ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+
+       /**
+        * sram memory access
+        */
+       ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+       ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+
+       /*
+        * err set reg : for notification of hb failure in fcmode
+        */
+       ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn)        ((__fn) * 8)
+static void
+bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
+{
+       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       u32     r32;
+
+       /**
+        * For catapult, base port id on personality register and IOC type
+        */
+       r32 = bfa_reg_read(rb + FNC_PERS_REG);
+       r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+       ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+       bfa_trc(ioc, bfa_ioc_pcifn(ioc));
+       bfa_trc(ioc, ioc->port_id);
+}
+
+/**
+ * Set interrupt mode for a function: INTX or MSIX
+ */
+static void
+bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
+{
+       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       u32     r32, mode;
+
+       r32 = bfa_reg_read(rb + FNC_PERS_REG);
+       bfa_trc(ioc, r32);
+
+       mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+               __F0_INTX_STATUS;
+
+       /**
+        * If already in desired mode, do not change anything
+        */
+       if (!msix && mode)
+               return;
+
+       if (msix)
+               mode = __F0_INTX_STATUS_MSIX;
+       else
+               mode = __F0_INTX_STATUS_INTA;
+
+       r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+       r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+       bfa_trc(ioc, r32);
+
+       bfa_reg_write(rb + FNC_PERS_REG, r32);
+}
+
+static bfa_status_t
+bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc)
+{
+       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       u32     pll_sclk, pll_fclk, r32;
+
+       /*
+        *  Hold semaphore so that nobody can access the chip during init.
+        */
+       bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
+
+       pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST |
+               __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) |
+               __APP_PLL_312_JITLMT0_1(3U) |
+               __APP_PLL_312_CNTLMT0_1(1U);
+       pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST |
+               __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
+               __APP_PLL_425_JITLMT0_1(3U) |
+               __APP_PLL_425_CNTLMT0_1(1U);
+
+       /**
+        *      For catapult, choose operational mode FC/FCoE
+        */
+       if (ioc->fcmode) {
+               bfa_reg_write((rb + OP_MODE), 0);
+               bfa_reg_write((rb + ETH_MAC_SER_REG),
+                               __APP_EMS_CMLCKSEL |
+                               __APP_EMS_REFCKBUFEN2 |
+                               __APP_EMS_CHANNEL_SEL);
+       } else {
+               ioc->pllinit = BFA_TRUE;
+               bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
+               bfa_reg_write((rb + ETH_MAC_SER_REG),
+                                __APP_EMS_REFCKBUFEN1);
+       }
+
+       bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
+       bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
+
+       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk |
+               __APP_PLL_312_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk |
+               __APP_PLL_425_LOGIC_SOFT_RESET);
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk |
+               __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk |
+               __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE);
+
+       /**
+        * Wait for PLLs to lock.
+        */
+       bfa_reg_read(rb + HOSTFN0_INT_MSK);
+       bfa_os_udelay(2000);
+       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+
+       bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk |
+               __APP_PLL_312_ENABLE);
+       bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk |
+               __APP_PLL_425_ENABLE);
+
+       bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
+       bfa_os_udelay(1000);
+       r32 = bfa_reg_read((rb + MBIST_STAT_REG));
+       bfa_trc(ioc, r32);
+       /*
+        *  release semaphore.
+        */
+       bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+       return BFA_STATUS_OK;
+}
+
+/**
+ * Cleanup hw semaphore and usecnt registers
+ */
+static void
+bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
+{
+
+       if (ioc->cna) {
+               bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+               bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0);
+               bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+       }
+
+       /*
+        * Read the hw sem reg to make sure that it is locked
+        * before we clear it. If it is not locked, writing 1
+        * will lock it instead of clearing it.
+        */
+       bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+       bfa_ioc_hw_sem_release(ioc);
+}
index d7ab792..a76de26 100644 (file)
@@ -172,6 +172,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
         */
        if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
                iocfc->hwif.hw_reginit = bfa_hwct_reginit;
+               iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack;
                iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
                iocfc->hwif.hw_msix_init = bfa_hwct_msix_init;
                iocfc->hwif.hw_msix_install = bfa_hwct_msix_install;
@@ -180,6 +181,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
                iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
        } else {
                iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
+               iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack;
                iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
                iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
                iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install;
@@ -336,8 +338,10 @@ bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
                        bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
                else
                        bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
-       } else
-               bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+       } else {
+               if (bfa->iocfc.cfgdone)
+                       bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+       }
 }
 
 static void
@@ -619,8 +623,6 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 
        bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod,
                bfa->trcmod, bfa->aen, bfa->logm);
-       bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
-       bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
 
        /**
         * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
@@ -628,6 +630,9 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        if (0)
                bfa_ioc_set_fcmode(&bfa->ioc);
 
+       bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
+       bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
+
        bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
        bfa_iocfc_mem_claim(bfa, cfg, meminfo);
        bfa_timer_init(&bfa->timer_mod);
@@ -654,7 +659,6 @@ bfa_iocfc_init(struct bfa_s *bfa)
 {
        bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
        bfa_ioc_enable(&bfa->ioc);
-       bfa_msix_install(bfa);
 }
 
 /**
@@ -797,6 +801,11 @@ bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
                return BFA_STATUS_DEVBUSY;
        }
 
+       if (!bfa_iocfc_is_operational(bfa)) {
+               bfa_trc(bfa, 0);
+               return BFA_STATUS_IOC_NON_OP;
+       }
+
        iocfc->stats_busy = BFA_TRUE;
        iocfc->stats_ret = stats;
        iocfc->stats_cbfn = cbfn;
@@ -817,6 +826,11 @@ bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
                return BFA_STATUS_DEVBUSY;
        }
 
+       if (!bfa_iocfc_is_operational(bfa)) {
+               bfa_trc(bfa, 0);
+               return BFA_STATUS_IOC_NON_OP;
+       }
+
        iocfc->stats_busy = BFA_TRUE;
        iocfc->stats_cbfn = cbfn;
        iocfc->stats_cbarg = cbarg;
index ce9a830..fbb4bdc 100644 (file)
@@ -54,6 +54,7 @@ struct bfa_msix_s {
  */
 struct bfa_hwif_s {
        void (*hw_reginit)(struct bfa_s *bfa);
+       void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq);
        void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
        void (*hw_msix_init)(struct bfa_s *bfa, int nvecs);
        void (*hw_msix_install)(struct bfa_s *bfa);
@@ -143,6 +144,7 @@ void bfa_msix_rspq(struct bfa_s *bfa, int vec);
 void bfa_msix_lpu_err(struct bfa_s *bfa, int vec);
 
 void bfa_hwcb_reginit(struct bfa_s *bfa);
+void bfa_hwcb_reqq_ack(struct bfa_s *bfa, int rspq);
 void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
 void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwcb_msix_install(struct bfa_s *bfa);
@@ -151,6 +153,7 @@ void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
 void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
                        u32 *nvecs, u32 *maxvec);
 void bfa_hwct_reginit(struct bfa_s *bfa);
+void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq);
 void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
 void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwct_msix_install(struct bfa_s *bfa);
index f81d359..5b107ab 100644 (file)
@@ -149,7 +149,7 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -194,7 +194,7 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -259,7 +259,7 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -317,7 +317,7 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -377,7 +377,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -419,7 +419,7 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -467,7 +467,7 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -516,7 +516,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -544,7 +544,7 @@ bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -577,7 +577,7 @@ bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
@@ -605,7 +605,7 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ioim->bfa, event);
        }
 }
 
index eabf7d3..a914ff2 100644 (file)
@@ -144,7 +144,7 @@ bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -175,7 +175,7 @@ bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -212,7 +212,7 @@ bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -247,7 +247,7 @@ bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -275,7 +275,7 @@ bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -317,7 +317,7 @@ bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -348,7 +348,7 @@ bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -385,7 +385,7 @@ bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -413,7 +413,7 @@ bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -442,7 +442,7 @@ bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -470,7 +470,7 @@ bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -502,7 +502,7 @@ bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -538,7 +538,7 @@ bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -559,7 +559,7 @@ bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
@@ -583,7 +583,7 @@ bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->bfa, event);
        }
 }
 
index 9844b45..ad06f61 100644 (file)
@@ -18,6 +18,7 @@
 #include <bfa.h>
 #include <bfi/bfi_lps.h>
 #include <cs/bfa_debug.h>
+#include <defs/bfa_defs_pci.h>
 
 BFA_TRC_FILE(HAL, LPS);
 BFA_MODULE(lps);
@@ -25,6 +26,12 @@ BFA_MODULE(lps);
 #define BFA_LPS_MIN_LPORTS     (1)
 #define BFA_LPS_MAX_LPORTS     (256)
 
+/*
+ * Maximum Vports supported per physical port or vf.
+ */
+#define BFA_LPS_MAX_VPORTS_SUPP_CB  255
+#define BFA_LPS_MAX_VPORTS_SUPP_CT  190
+
 /**
  * forward declarations
  */
@@ -49,7 +56,7 @@ static void bfa_lps_send_login(struct bfa_lps_s *lps);
 static void bfa_lps_send_logout(struct bfa_lps_s *lps);
 static void bfa_lps_login_comp(struct bfa_lps_s *lps);
 static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
-
+static void bfa_lps_cvl_event(struct bfa_lps_s *lps);
 
 /**
  *  lps_pvt BFA LPS private functions
@@ -62,6 +69,7 @@ enum bfa_lps_event {
        BFA_LPS_SM_RESUME       = 4,    /* space present in reqq queue  */
        BFA_LPS_SM_DELETE       = 5,    /* lps delete from user         */
        BFA_LPS_SM_OFFLINE      = 6,    /* Link is offline              */
+       BFA_LPS_SM_RX_CVL       = 7,    /* Rx clear virtual link        */
 };
 
 static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
@@ -91,6 +99,12 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
                        bfa_sm_set_state(lps, bfa_lps_sm_login);
                        bfa_lps_send_login(lps);
                }
+               if (lps->fdisc)
+                       bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                       BFA_PL_EID_LOGIN, 0, "FDISC Request");
+               else
+                       bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                       BFA_PL_EID_LOGIN, 0, "FLOGI Request");
                break;
 
        case BFA_LPS_SM_LOGOUT:
@@ -101,6 +115,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
                bfa_lps_free(lps);
                break;
 
+       case BFA_LPS_SM_RX_CVL:
        case BFA_LPS_SM_OFFLINE:
                break;
 
@@ -112,7 +127,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -127,10 +142,25 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
 
        switch (event) {
        case BFA_LPS_SM_FWRSP:
-               if (lps->status == BFA_STATUS_OK)
+               if (lps->status == BFA_STATUS_OK) {
                        bfa_sm_set_state(lps, bfa_lps_sm_online);
-               else
+                       if (lps->fdisc)
+                               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                               BFA_PL_EID_LOGIN, 0, "FDISC Accept");
+                       else
+                               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                               BFA_PL_EID_LOGIN, 0, "FLOGI Accept");
+               } else {
                        bfa_sm_set_state(lps, bfa_lps_sm_init);
+                       if (lps->fdisc)
+                               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                               BFA_PL_EID_LOGIN, 0,
+                               "FDISC Fail (RJT or timeout)");
+                       else
+                               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                               BFA_PL_EID_LOGIN, 0,
+                               "FLOGI Fail (RJT or timeout)");
+               }
                bfa_lps_login_comp(lps);
                break;
 
@@ -139,7 +169,7 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -162,8 +192,16 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
                bfa_reqq_wcancel(&lps->wqe);
                break;
 
+       case BFA_LPS_SM_RX_CVL:
+               /*
+                * Login was not even sent out; so when getting out
+                * of this state, it will appear like a login retry
+                * after Clear virtual link
+                */
+               break;
+
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -185,6 +223,17 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
                        bfa_sm_set_state(lps, bfa_lps_sm_logout);
                        bfa_lps_send_logout(lps);
                }
+               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                       BFA_PL_EID_LOGO, 0, "Logout");
+               break;
+
+       case BFA_LPS_SM_RX_CVL:
+               bfa_sm_set_state(lps, bfa_lps_sm_init);
+
+               /* Let the vport module know about this event */
+               bfa_lps_cvl_event(lps);
+               bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+                       BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
                break;
 
        case BFA_LPS_SM_OFFLINE:
@@ -193,7 +242,7 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -217,7 +266,7 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -242,7 +291,7 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(lps->bfa, event);
        }
 }
 
@@ -396,6 +445,20 @@ bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
 }
 
 /**
+ * Firmware received a Clear virtual link request (for FCoE)
+ */
+static void
+bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl)
+{
+       struct bfa_lps_mod_s    *mod = BFA_LPS_MOD(bfa);
+       struct bfa_lps_s        *lps;
+
+       lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag);
+
+       bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL);
+}
+
+/**
  * Space is available in request queue, resume queueing request to firmware.
  */
 static void
@@ -531,7 +594,48 @@ bfa_lps_logout_comp(struct bfa_lps_s *lps)
                bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
 }
 
+/**
+ * Clear virtual link completion handler for non-fcs
+ */
+static void
+bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete)
+{
+       struct bfa_lps_s *lps   = arg;
+
+       if (!complete)
+               return;
+
+       /* Clear virtual link to base port will result in link down */
+       if (lps->fdisc)
+               bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
+}
+
+/**
+ * Received Clear virtual link event --direct call for fcs,
+ * queue for others
+ */
+static void
+bfa_lps_cvl_event(struct bfa_lps_s *lps)
+{
+       if (!lps->bfa->fcs) {
+               bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb,
+                               lps);
+               return;
+       }
+
+       /* Clear virtual link to base port will result in link down */
+       if (lps->fdisc)
+               bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
+}
 
+u32
+bfa_lps_get_max_vport(struct bfa_s *bfa)
+{
+       if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT)
+               return BFA_LPS_MAX_VPORTS_SUPP_CT;
+       else
+               return BFA_LPS_MAX_VPORTS_SUPP_CB;
+}
 
 /**
  *  lps_public BFA LPS public functions
@@ -752,6 +856,14 @@ bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
        return lps->lsrjt_expl;
 }
 
+/**
+ * Return fpma/spma MAC for lport
+ */
+struct mac_s
+bfa_lps_get_lp_mac(struct bfa_lps_s *lps)
+{
+       return lps->lp_mac;
+}
 
 /**
  * LPS firmware message class handler.
@@ -773,6 +885,10 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                bfa_lps_logout_rsp(bfa, msg.logout_rsp);
                break;
 
+       case BFI_LPS_H2I_CVL_EVENT:
+               bfa_lps_rx_cvl_event(bfa, msg.cvl_event);
+               break;
+
        default:
                bfa_trc(bfa, m->mhdr.msg_id);
                bfa_assert(0);
index 32eda8e..a7fcc80 100644 (file)
@@ -24,7 +24,7 @@
  */
 struct bfa_module_s *hal_mods[] = {
        &hal_mod_sgpg,
-       &hal_mod_pport,
+       &hal_mod_fcport,
        &hal_mod_fcxp,
        &hal_mod_lps,
        &hal_mod_uf,
@@ -45,7 +45,7 @@ bfa_isr_func_t  bfa_isrs[BFI_MC_MAX] = {
        bfa_isr_unhandled,      /* BFI_MC_DIAG */
        bfa_isr_unhandled,      /* BFI_MC_FLASH */
        bfa_isr_unhandled,      /* BFI_MC_CEE */
-       bfa_pport_isr,          /* BFI_MC_PORT */
+       bfa_fcport_isr,         /* BFI_MC_FCPORT */
        bfa_isr_unhandled,      /* BFI_MC_IOCFC */
        bfa_isr_unhandled,      /* BFI_MC_LL */
        bfa_uf_isr,             /* BFI_MC_UF */
index 96f7053..f554c2f 100644 (file)
@@ -29,7 +29,7 @@
 
 
 struct bfa_modules_s {
-       struct bfa_pport_s      pport;  /*  physical port module        */
+       struct bfa_fcport_s     fcport; /*  fc port module      */
        struct bfa_fcxp_mod_s fcxp_mod; /*  fcxp module         */
        struct bfa_lps_mod_s lps_mod;   /*  fcxp module         */
        struct bfa_uf_mod_s uf_mod;     /*  unsolicited frame module    */
index 51f698a..40e256e 100644 (file)
 #include "bfa_intr_priv.h"
 
 /**
- * BFA physical port data structure
+ * Link notification data structure
  */
-struct bfa_pport_s {
+struct bfa_fcport_ln_s {
+       struct bfa_fcport_s     *fcport;
+       bfa_sm_t                sm;
+       struct bfa_cb_qe_s      ln_qe;  /*  BFA callback queue elem for ln */
+       enum bfa_pport_linkstate ln_event; /*  ln event for callback */
+};
+
+/**
+ * BFA FC port data structure
+ */
+struct bfa_fcport_s {
        struct bfa_s            *bfa;   /*  parent BFA instance */
        bfa_sm_t                sm;     /*  port state machine */
        wwn_t                   nwwn;   /*  node wwn of physical port */
@@ -36,6 +46,8 @@ struct bfa_pport_s {
        enum bfa_pport_topology topology;       /*  current topology */
        u8                      myalpa; /*  my ALPA in LOOP topology */
        u8                      rsvd[3];
+       u32             mypid:24;
+       u32             rsvd_b:8;
        struct bfa_pport_cfg_s  cfg;    /*  current port configuration */
        struct bfa_qos_attr_s  qos_attr;   /* QoS Attributes */
        struct bfa_qos_vc_attr_s qos_vc_attr;  /*  VC info from ELP */
@@ -49,42 +61,31 @@ struct bfa_pport_s {
        void                    (*event_cbfn) (void *cbarg,
                                                bfa_pport_event_t event);
        union {
-               union bfi_pport_i2h_msg_u i2hmsg;
+               union bfi_fcport_i2h_msg_u i2hmsg;
        } event_arg;
        void                    *bfad;  /*  BFA driver handle */
+       struct bfa_fcport_ln_s   ln; /* Link Notification */
        struct bfa_cb_qe_s              hcb_qe; /*  BFA callback queue elem */
-       enum bfa_pport_linkstate        hcb_event;
-                                       /*  link event for callback */
+       struct bfa_timer_s      timer;  /*  timer */
        u32             msgtag; /*  fimrware msg tag for reply */
        u8                      *stats_kva;
        u64             stats_pa;
-       union bfa_pport_stats_u *stats; /*  pport stats */
-       u32             mypid:24;
-       u32             rsvd_b:8;
-       struct bfa_timer_s      timer;  /*  timer */
-       union bfa_pport_stats_u         *stats_ret;
-                                       /*  driver stats location */
-       bfa_status_t            stats_status;
-                                       /*  stats/statsclr status */
-       bfa_boolean_t           stats_busy;
-                                       /*  outstanding stats/statsclr */
-       bfa_boolean_t           stats_qfull;
-       bfa_boolean_t           diag_busy;
-                                       /*  diag busy status */
-       bfa_boolean_t           beacon;
-                                       /*  port beacon status */
-       bfa_boolean_t           link_e2e_beacon;
-                                       /*  link beacon status */
-       bfa_cb_pport_t          stats_cbfn;
-                                       /*  driver callback function */
-       void                    *stats_cbarg;
-                                       /* *!< user callback arg */
+       union bfa_fcport_stats_u *stats;
+       union bfa_fcport_stats_u *stats_ret; /*  driver stats location */
+       bfa_status_t            stats_status; /*  stats/statsclr status */
+       bfa_boolean_t           stats_busy; /*  outstanding stats/statsclr */
+       bfa_boolean_t           stats_qfull;
+       bfa_cb_pport_t          stats_cbfn; /*  driver callback function */
+       void                    *stats_cbarg; /* *!< user callback arg */
+       bfa_boolean_t           diag_busy; /*  diag busy status */
+       bfa_boolean_t           beacon; /*  port beacon status */
+       bfa_boolean_t           link_e2e_beacon; /*  link beacon status */
 };
 
-#define BFA_PORT_MOD(__bfa)    (&(__bfa)->modules.pport)
+#define BFA_FCPORT_MOD(__bfa)  (&(__bfa)->modules.fcport)
 
 /*
  * public functions
  */
-void   bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void   bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 #endif /* __BFA_PORT_PRIV_H__ */
index 0747a6b..be80fc7 100644 (file)
@@ -101,7 +101,7 @@ extern bfa_boolean_t bfa_auto_recover;
 extern struct bfa_module_s hal_mod_flash;
 extern struct bfa_module_s hal_mod_fcdiag;
 extern struct bfa_module_s hal_mod_sgpg;
-extern struct bfa_module_s hal_mod_pport;
+extern struct bfa_module_s hal_mod_fcport;
 extern struct bfa_module_s hal_mod_fcxp;
 extern struct bfa_module_s hal_mod_lps;
 extern struct bfa_module_s hal_mod_uf;
index 3e1990a..7c509fa 100644 (file)
@@ -114,7 +114,7 @@ bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_un_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -146,7 +146,7 @@ bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_cr_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -183,7 +183,7 @@ bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_fwc_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -224,7 +224,7 @@ bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_fwc_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -296,7 +296,7 @@ bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_on_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -329,7 +329,7 @@ bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_fwd_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -359,7 +359,7 @@ bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_fwd_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -394,7 +394,7 @@ bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_off_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -421,7 +421,7 @@ bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -446,7 +446,7 @@ bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -477,7 +477,7 @@ bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
 
        default:
                bfa_stats(rp, sm_delp_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -512,7 +512,7 @@ bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
 
        default:
                bfa_stats(rp, sm_offp_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
@@ -550,7 +550,7 @@ bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
        default:
                bfa_stats(rp, sm_iocd_unexp);
-               bfa_assert(0);
+               bfa_sm_fault(rp->bfa, event);
        }
 }
 
index b3562dc..a7a8261 100644 (file)
  * !!! needed between trace utility and driver version
  */
 enum {
-       BFA_TRC_HAL_IOC         = 1,
-       BFA_TRC_HAL_INTR        = 2,
-       BFA_TRC_HAL_FCXP        = 3,
-       BFA_TRC_HAL_UF          = 4,
-       BFA_TRC_HAL_DIAG        = 5,
-       BFA_TRC_HAL_RPORT       = 6,
-       BFA_TRC_HAL_FCPIM       = 7,
-       BFA_TRC_HAL_IOIM        = 8,
-       BFA_TRC_HAL_TSKIM       = 9,
-       BFA_TRC_HAL_ITNIM       = 10,
-       BFA_TRC_HAL_PPORT       = 11,
-       BFA_TRC_HAL_SGPG        = 12,
-       BFA_TRC_HAL_FLASH       = 13,
-       BFA_TRC_HAL_DEBUG       = 14,
-       BFA_TRC_HAL_WWN         = 15,
-       BFA_TRC_HAL_FLASH_RAW   = 16,
-       BFA_TRC_HAL_SBOOT       = 17,
-       BFA_TRC_HAL_SBOOT_IO    = 18,
-       BFA_TRC_HAL_SBOOT_INTR  = 19,
-       BFA_TRC_HAL_SBTEST      = 20,
-       BFA_TRC_HAL_IPFC        = 21,
-       BFA_TRC_HAL_IOCFC       = 22,
-       BFA_TRC_HAL_FCPTM       = 23,
-       BFA_TRC_HAL_IOTM        = 24,
-       BFA_TRC_HAL_TSKTM       = 25,
-       BFA_TRC_HAL_TIN         = 26,
-       BFA_TRC_HAL_LPS         = 27,
-       BFA_TRC_HAL_FCDIAG      = 28,
-       BFA_TRC_HAL_PBIND       = 29,
-       BFA_TRC_HAL_IOCFC_CT    = 30,
-       BFA_TRC_HAL_IOCFC_CB    = 31,
-       BFA_TRC_HAL_IOCFC_Q     = 32,
+       BFA_TRC_HAL_INTR        = 1,
+       BFA_TRC_HAL_FCXP        = 2,
+       BFA_TRC_HAL_UF          = 3,
+       BFA_TRC_HAL_RPORT       = 4,
+       BFA_TRC_HAL_FCPIM       = 5,
+       BFA_TRC_HAL_IOIM        = 6,
+       BFA_TRC_HAL_TSKIM       = 7,
+       BFA_TRC_HAL_ITNIM       = 8,
+       BFA_TRC_HAL_FCPORT      = 9,
+       BFA_TRC_HAL_SGPG        = 10,
+       BFA_TRC_HAL_FLASH       = 11,
+       BFA_TRC_HAL_DEBUG       = 12,
+       BFA_TRC_HAL_WWN         = 13,
+       BFA_TRC_HAL_FLASH_RAW   = 14,
+       BFA_TRC_HAL_SBOOT       = 15,
+       BFA_TRC_HAL_SBOOT_IO    = 16,
+       BFA_TRC_HAL_SBOOT_INTR  = 17,
+       BFA_TRC_HAL_SBTEST      = 18,
+       BFA_TRC_HAL_IPFC        = 19,
+       BFA_TRC_HAL_IOCFC       = 20,
+       BFA_TRC_HAL_FCPTM       = 21,
+       BFA_TRC_HAL_IOTM        = 22,
+       BFA_TRC_HAL_TSKTM       = 23,
+       BFA_TRC_HAL_TIN         = 24,
+       BFA_TRC_HAL_LPS         = 25,
+       BFA_TRC_HAL_FCDIAG      = 26,
+       BFA_TRC_HAL_PBIND       = 27,
+       BFA_TRC_HAL_IOCFC_CT    = 28,
+       BFA_TRC_HAL_IOCFC_CB    = 29,
+       BFA_TRC_HAL_IOCFC_Q     = 30,
 };
 
 #endif /* __BFA_TRCMOD_PRIV_H__ */
index ff7a4dc..ad9aaae 100644 (file)
@@ -110,7 +110,7 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -146,7 +146,7 @@ bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -178,7 +178,7 @@ bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -207,7 +207,7 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -242,7 +242,7 @@ bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -277,7 +277,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
@@ -303,7 +303,7 @@ bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(tskim->bfa, event);
        }
 }
 
index b52b773..6bff08e 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/kthread.h>
 #include "bfad_drv.h"
 #include "bfad_im.h"
 #include "bfad_tm.h"
@@ -53,6 +54,7 @@ static int      log_level = BFA_LOG_WARNING;
 static int      ioc_auto_recover = BFA_TRUE;
 static int      ipfc_enable = BFA_FALSE;
 static int      ipfc_mtu = -1;
+static int     fdmi_enable = BFA_TRUE;
 int            bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
 int            bfa_linkup_delay = -1;
 
@@ -74,6 +76,7 @@ module_param(log_level, int, S_IRUGO | S_IWUSR);
 module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
 module_param(ipfc_enable, int, S_IRUGO | S_IWUSR);
 module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR);
+module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
 module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
 
 /*
@@ -95,6 +98,8 @@ bfad_fc4_probe(struct bfad_s *bfad)
 
        if (ipfc_enable)
                bfad_ipfc_probe(bfad);
+
+       bfad->bfad_flags |= BFAD_FC4_PROBE_DONE;
 ext:
        return rc;
 }
@@ -106,6 +111,7 @@ bfad_fc4_probe_undo(struct bfad_s *bfad)
        bfad_tm_probe_undo(bfad);
        if (ipfc_enable)
                bfad_ipfc_probe_undo(bfad);
+       bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE;
 }
 
 static void
@@ -173,9 +179,19 @@ bfa_cb_init(void *drv, bfa_status_t init_status)
 {
        struct bfad_s  *bfad = drv;
 
-       if (init_status == BFA_STATUS_OK)
+       if (init_status == BFA_STATUS_OK) {
                bfad->bfad_flags |= BFAD_HAL_INIT_DONE;
 
+               /* If BFAD_HAL_INIT_FAIL flag is set:
+                * Wake up the kernel thread to start
+                * the bfad operations after HAL init done
+                */
+               if ((bfad->bfad_flags & BFAD_HAL_INIT_FAIL)) {
+                       bfad->bfad_flags &= ~BFAD_HAL_INIT_FAIL;
+                       wake_up_process(bfad->bfad_tsk);
+               }
+       }
+
        complete(&bfad->comp);
 }
 
@@ -648,7 +664,7 @@ bfad_fcs_port_cfg(struct bfad_s *bfad)
 
        sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no);
        memcpy(port_cfg.sym_name.symname, symname, strlen(symname));
-       bfa_pport_get_attr(&bfad->bfa, &attr);
+       bfa_fcport_get_attr(&bfad->bfa, &attr);
        port_cfg.nwwn = attr.nwwn;
        port_cfg.pwwn = attr.pwwn;
 
@@ -661,7 +677,6 @@ bfad_drv_init(struct bfad_s *bfad)
        bfa_status_t    rc;
        unsigned long   flags;
        struct bfa_fcs_driver_info_s driver_info;
-       int             i;
 
        bfad->cfg_data.rport_del_timeout = rport_del_timeout;
        bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth;
@@ -681,12 +696,7 @@ bfad_drv_init(struct bfad_s *bfad)
        bfa_init_log(&bfad->bfa, bfad->logmod);
        bfa_init_trc(&bfad->bfa, bfad->trcmod);
        bfa_init_aen(&bfad->bfa, bfad->aen);
-       INIT_LIST_HEAD(&bfad->file_q);
-       INIT_LIST_HEAD(&bfad->file_free_q);
-       for (i = 0; i < BFAD_AEN_MAX_APPS; i++) {
-               bfa_q_qe_init(&bfad->file_buf[i].qe);
-               list_add_tail(&bfad->file_buf[i].qe, &bfad->file_free_q);
-       }
+       memset(bfad->file_map, 0, sizeof(bfad->file_map));
        bfa_init_plog(&bfad->bfa, &bfad->plog_buf);
        bfa_plog_init(&bfad->plog_buf);
        bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
@@ -746,8 +756,16 @@ bfad_drv_init(struct bfad_s *bfad)
        bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod);
        bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod);
        bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen);
-       bfa_fcs_init(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
+       bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
+
+       /* Do FCS init only when HAL init is done */
+       if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+               bfa_fcs_init(&bfad->bfa_fcs);
+               bfad->bfad_flags |= BFAD_FCS_INIT_DONE;
+       }
+
        bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info);
+       bfa_fcs_set_fdmi_param(&bfad->bfa_fcs, fdmi_enable);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
        bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
@@ -763,12 +781,21 @@ out_hal_mem_alloc_failure:
 void
 bfad_drv_uninit(struct bfad_s *bfad)
 {
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       init_completion(&bfad->comp);
+       bfa_stop(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       wait_for_completion(&bfad->comp);
+
        del_timer_sync(&bfad->hal_tmo);
        bfa_isr_disable(&bfad->bfa);
        bfa_detach(&bfad->bfa);
        bfad_remove_intr(bfad);
-       bfa_assert(list_empty(&bfad->file_q));
        bfad_hal_mem_release(bfad);
+
+       bfad->bfad_flags &= ~BFAD_DRV_INIT_DONE;
 }
 
 void
@@ -859,6 +886,86 @@ bfad_drv_log_level_set(struct bfad_s *bfad)
                bfa_log_set_level_all(&bfad->log_data, log_level);
 }
 
+bfa_status_t
+bfad_start_ops(struct bfad_s *bfad)
+{
+       int retval;
+
+       /* PPORT FCS config */
+       bfad_fcs_port_cfg(bfad);
+
+       retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM);
+       if (retval != BFA_STATUS_OK)
+               goto out_cfg_pport_failure;
+
+       /* BFAD level FC4 (IM/TM/IPFC) specific resource allocation */
+       retval = bfad_fc4_probe(bfad);
+       if (retval != BFA_STATUS_OK) {
+               printk(KERN_WARNING "bfad_fc4_probe failed\n");
+               goto out_fc4_probe_failure;
+       }
+
+       bfad_drv_start(bfad);
+
+       /*
+        * If bfa_linkup_delay is set to -1 default; try to retrive the
+        * value using the bfad_os_get_linkup_delay(); else use the
+        * passed in module param value as the bfa_linkup_delay.
+        */
+       if (bfa_linkup_delay < 0) {
+
+               bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
+               bfad_os_rport_online_wait(bfad);
+               bfa_linkup_delay = -1;
+
+       } else {
+               bfad_os_rport_online_wait(bfad);
+       }
+
+       bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name);
+
+       return BFA_STATUS_OK;
+
+out_fc4_probe_failure:
+       bfad_fc4_probe_undo(bfad);
+       bfad_uncfg_pport(bfad);
+out_cfg_pport_failure:
+       return BFA_STATUS_FAILED;
+}
+
+int
+bfad_worker (void *ptr)
+{
+       struct bfad_s *bfad;
+       unsigned long   flags;
+
+       bfad = (struct bfad_s *)ptr;
+
+       while (!kthread_should_stop()) {
+
+               /* Check if the FCS init is done from bfad_drv_init;
+                * if not done do FCS init and set the flag.
+                */
+               if (!(bfad->bfad_flags & BFAD_FCS_INIT_DONE)) {
+                       spin_lock_irqsave(&bfad->bfad_lock, flags);
+                       bfa_fcs_init(&bfad->bfa_fcs);
+                       bfad->bfad_flags |= BFAD_FCS_INIT_DONE;
+                       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               }
+
+               /* Start the bfad operations after HAL init done */
+               bfad_start_ops(bfad);
+
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               bfad->bfad_tsk = NULL;
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+               break;
+       }
+
+       return 0;
+}
+
  /*
   *  PCI_entry PCI driver entries * {
   */
@@ -871,7 +978,6 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct bfad_s  *bfad;
        int             error = -ENODEV, retval;
-       char            buf[16];
 
        /*
         * For single port cards - only claim function 0
@@ -902,8 +1008,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        bfa_trc(bfad, bfad_inst);
 
        bfad->logmod = &bfad->log_data;
-       sprintf(buf, "%d", bfad_inst);
-       bfa_log_init(bfad->logmod, buf, bfa_os_printf);
+       bfa_log_init(bfad->logmod, (char *)pci_name(pdev), bfa_os_printf);
 
        bfad_drv_log_level_set(bfad);
 
@@ -933,57 +1038,39 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        bfad->ref_count = 0;
        bfad->pport.bfad = bfad;
 
+       bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, "%s",
+                                       "bfad_worker");
+       if (IS_ERR(bfad->bfad_tsk)) {
+               printk(KERN_INFO "bfad[%d]: Kernel thread"
+                       " creation failed!\n",
+                       bfad->inst_no);
+               goto out_kthread_create_failure;
+       }
+
        retval = bfad_drv_init(bfad);
        if (retval != BFA_STATUS_OK)
                goto out_drv_init_failure;
        if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+               bfad->bfad_flags |= BFAD_HAL_INIT_FAIL;
                printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no);
                goto ok;
        }
 
-       /*
-        * PPORT FCS config
-        */
-       bfad_fcs_port_cfg(bfad);
-
-       retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM);
+       retval = bfad_start_ops(bfad);
        if (retval != BFA_STATUS_OK)
-               goto out_cfg_pport_failure;
-
-       /*
-        * BFAD level FC4 (IM/TM/IPFC) specific resource allocation
-        */
-       retval = bfad_fc4_probe(bfad);
-       if (retval != BFA_STATUS_OK) {
-               printk(KERN_WARNING "bfad_fc4_probe failed\n");
-               goto out_fc4_probe_failure;
-       }
+               goto out_start_ops_failure;
 
-       bfad_drv_start(bfad);
-
-       /*
-        * If bfa_linkup_delay is set to -1 default; try to retrive the
-        * value using the bfad_os_get_linkup_delay(); else use the
-        * passed in module param value as the bfa_linkup_delay.
-        */
-       if (bfa_linkup_delay < 0) {
-               bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
-               bfad_os_rport_online_wait(bfad);
-               bfa_linkup_delay = -1;
-       } else {
-               bfad_os_rport_online_wait(bfad);
-       }
+       kthread_stop(bfad->bfad_tsk);
+       bfad->bfad_tsk = NULL;
 
-       bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name);
 ok:
        return 0;
 
-out_fc4_probe_failure:
-       bfad_fc4_probe_undo(bfad);
-       bfad_uncfg_pport(bfad);
-out_cfg_pport_failure:
+out_start_ops_failure:
        bfad_drv_uninit(bfad);
 out_drv_init_failure:
+       kthread_stop(bfad->bfad_tsk);
+out_kthread_create_failure:
        mutex_lock(&bfad_mutex);
        bfad_inst--;
        list_del(&bfad->list_entry);
@@ -1008,6 +1095,11 @@ bfad_pci_remove(struct pci_dev *pdev)
 
        bfa_trc(bfad, bfad->inst_no);
 
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (bfad->bfad_tsk != NULL)
+               kthread_stop(bfad->bfad_tsk);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
        if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE)
            && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
 
@@ -1024,13 +1116,25 @@ bfad_pci_remove(struct pci_dev *pdev)
                goto remove_sysfs;
        }
 
-       if (bfad->bfad_flags & BFAD_HAL_START_DONE)
+       if (bfad->bfad_flags & BFAD_HAL_START_DONE) {
                bfad_drv_stop(bfad);
+       } else if (bfad->bfad_flags & BFAD_DRV_INIT_DONE) {
+               /* Invoking bfa_stop() before bfa_detach
+                * when HAL and DRV init are success
+                * but HAL start did not occur.
+                */
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               init_completion(&bfad->comp);
+               bfa_stop(&bfad->bfa);
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               wait_for_completion(&bfad->comp);
+       }
 
        bfad_remove_intr(bfad);
-
        del_timer_sync(&bfad->hal_tmo);
-       bfad_fc4_probe_undo(bfad);
+
+       if (bfad->bfad_flags & BFAD_FC4_PROBE_DONE)
+               bfad_fc4_probe_undo(bfad);
 
        if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE)
                bfad_uncfg_pport(bfad);
index 9129ae3..d97f691 100644 (file)
@@ -141,7 +141,7 @@ bfad_im_get_host_port_type(struct Scsi_Host *shost)
        struct bfad_s         *bfad = im_port->bfad;
        struct bfa_pport_attr_s attr;
 
-       bfa_pport_get_attr(&bfad->bfa, &attr);
+       bfa_fcport_get_attr(&bfad->bfa, &attr);
 
        switch (attr.port_type) {
        case BFA_PPORT_TYPE_NPORT:
@@ -173,7 +173,7 @@ bfad_im_get_host_port_state(struct Scsi_Host *shost)
        struct bfad_s         *bfad = im_port->bfad;
        struct bfa_pport_attr_s attr;
 
-       bfa_pport_get_attr(&bfad->bfa, &attr);
+       bfa_fcport_get_attr(&bfad->bfa, &attr);
 
        switch (attr.port_state) {
        case BFA_PPORT_ST_LINKDOWN:
@@ -229,8 +229,10 @@ bfad_im_get_host_speed(struct Scsi_Host *shost)
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
        struct bfa_pport_attr_s attr;
+       unsigned long   flags;
 
-       bfa_pport_get_attr(&bfad->bfa, &attr);
+       spin_lock_irqsave(shost->host_lock, flags);
+       bfa_fcport_get_attr(&bfad->bfa, &attr);
        switch (attr.speed) {
        case BFA_PPORT_SPEED_8GBPS:
                fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
@@ -248,6 +250,7 @@ bfad_im_get_host_speed(struct Scsi_Host *shost)
                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                break;
        }
+       spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
 /**
@@ -285,7 +288,7 @@ bfad_im_get_stats(struct Scsi_Host *shost)
        init_completion(&fcomp.comp);
        spin_lock_irqsave(&bfad->bfad_lock, flags);
        memset(hstats, 0, sizeof(struct fc_host_statistics));
-       rc = bfa_pport_get_stats(&bfad->bfa,
+       rc =  bfa_port_get_stats(BFA_FCPORT(&bfad->bfa),
                                     (union bfa_pport_stats_u *) hstats,
                                     bfad_hcb_comp, &fcomp);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -312,7 +315,8 @@ bfad_im_reset_stats(struct Scsi_Host *shost)
 
        init_completion(&fcomp.comp);
        spin_lock_irqsave(&bfad->bfad_lock, flags);
-       rc = bfa_pport_clear_stats(&bfad->bfa, bfad_hcb_comp, &fcomp);
+       rc = bfa_port_clear_stats(BFA_FCPORT(&bfad->bfa), bfad_hcb_comp,
+               &fcomp);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
        if (rc != BFA_STATUS_OK)
@@ -421,12 +425,10 @@ bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       ioc_attr.adapter_attr.serial_num);
+       bfa_get_adapter_serial_num(&bfad->bfa, serial_num);
+       return snprintf(buf, PAGE_SIZE, "%s\n", serial_num);
 }
 
 static ssize_t
@@ -437,11 +439,10 @@ bfad_im_model_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char model[BFA_ADAPTER_MODEL_NAME_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.model);
+       bfa_get_adapter_model(&bfad->bfa, model);
+       return snprintf(buf, PAGE_SIZE, "%s\n", model);
 }
 
 static ssize_t
@@ -452,12 +453,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       ioc_attr.adapter_attr.model_descr);
+       bfa_get_adapter_model(&bfad->bfa, model_descr);
+       return snprintf(buf, PAGE_SIZE, "%s\n", model_descr);
 }
 
 static ssize_t
@@ -482,14 +481,13 @@ bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
-
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
+       char model[BFA_ADAPTER_MODEL_NAME_LEN];
+       char fw_ver[BFA_VERSION_LEN];
 
+       bfa_get_adapter_model(&bfad->bfa, model);
+       bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver);
        return snprintf(buf, PAGE_SIZE, "Brocade %s FV%s DV%s\n",
-                       ioc_attr.adapter_attr.model,
-                       ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+               model, fw_ver, BFAD_DRIVER_VERSION);
 }
 
 static ssize_t
@@ -500,11 +498,10 @@ bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char hw_ver[BFA_VERSION_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.hw_ver);
+       bfa_get_pci_chip_rev(&bfad->bfa, hw_ver);
+       return snprintf(buf, PAGE_SIZE, "%s\n", hw_ver);
 }
 
 static ssize_t
@@ -522,12 +519,10 @@ bfad_im_optionrom_version_show(struct device *dev,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char optrom_ver[BFA_VERSION_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       ioc_attr.adapter_attr.optrom_ver);
+       bfa_get_adapter_optrom_ver(&bfad->bfa, optrom_ver);
+       return snprintf(buf, PAGE_SIZE, "%s\n", optrom_ver);
 }
 
 static ssize_t
@@ -538,11 +533,10 @@ bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
+       char fw_ver[BFA_VERSION_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.fw_ver);
+       bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver);
+       return snprintf(buf, PAGE_SIZE, "%s\n", fw_ver);
 }
 
 static ssize_t
@@ -553,11 +547,9 @@ bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr,
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
        struct bfad_s         *bfad = im_port->bfad;
-       struct bfa_ioc_attr_s  ioc_attr;
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
-       return snprintf(buf, PAGE_SIZE, "%d\n", ioc_attr.adapter_attr.nports);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+               bfa_get_nports(&bfad->bfa));
 }
 
 static ssize_t
index 4d3312d..bf01020 100644 (file)
@@ -17,9 +17,6 @@
 
 #ifndef __BFAD_ATTR_H__
 #define __BFAD_ATTR_H__
-/**
- *  bfad_attr.h VMware driver configuration interface module.
- */
 
 /**
  *  FC_transport_template FC transport template
@@ -52,12 +49,6 @@ bfad_im_get_starget_port_name(struct scsi_target *starget);
 void
 bfad_im_get_host_port_id(struct Scsi_Host *shost);
 
-/**
- * FC transport template entry, issue a LIP.
- */
-int
-bfad_im_issue_fc_host_lip(struct Scsi_Host *shost);
-
 struct Scsi_Host*
 bfad_os_starget_to_shost(struct scsi_target *starget);
 
index 172c81e..107848c 100644 (file)
@@ -46,7 +46,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "2.0.0.0"
+#define BFAD_DRIVER_VERSION    "2.1.2.1"
 #endif
 
 
@@ -62,7 +62,9 @@
 #define BFAD_HAL_START_DONE                    0x00000010
 #define BFAD_PORT_ONLINE                       0x00000020
 #define BFAD_RPORT_ONLINE                      0x00000040
-
+#define BFAD_FCS_INIT_DONE                      0x00000080
+#define BFAD_HAL_INIT_FAIL                      0x00000100
+#define BFAD_FC4_PROBE_DONE                     0x00000200
 #define BFAD_PORT_DELETE                       0x00000001
 
 /*
@@ -137,12 +139,16 @@ struct bfad_cfg_param_s {
        u32        binding_method;
 };
 
-#define BFAD_AEN_MAX_APPS 8
-struct bfad_aen_file_s {
-       struct list_head  qe;
-       struct bfad_s *bfad;
-       s32 ri;
-       s32 app_id;
+union bfad_tmp_buf {
+       /* From struct bfa_adapter_attr_s */
+       char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+       char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+       char            model[BFA_ADAPTER_MODEL_NAME_LEN];
+       char            fw_ver[BFA_VERSION_LEN];
+       char            optrom_ver[BFA_VERSION_LEN];
+
+       /* From struct bfa_ioc_pci_attr_s */
+       u8         chip_rev[BFA_IOC_CHIP_REV_LEN];  /*  chip revision */
 };
 
 /*
@@ -168,6 +174,7 @@ struct bfad_s {
        u32        inst_no;     /* BFAD instance number */
        u32        bfad_flags;
        spinlock_t      bfad_lock;
+       struct task_struct *bfad_tsk;
        struct bfad_cfg_param_s cfg_data;
        struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY];
        int             nvec;
@@ -183,18 +190,12 @@ struct bfad_s {
        struct bfa_log_mod_s  *logmod;
        struct bfa_aen_s      *aen;
        struct bfa_aen_s       aen_buf;
-       struct bfad_aen_file_s file_buf[BFAD_AEN_MAX_APPS];
-       struct list_head         file_q;
-       struct list_head         file_free_q;
+       void            *file_map[BFA_AEN_MAX_APP];
        struct bfa_plog_s      plog_buf;
        int             ref_count;
        bfa_boolean_t   ipfc_enabled;
+       union bfad_tmp_buf tmp_buf;
        struct fc_host_statistics link_stats;
-
-       struct kobject *bfa_kobj;
-       struct kobject *ioc_kobj;
-       struct kobject *pport_kobj;
-       struct kobject *lport_kobj;
 };
 
 /*
@@ -258,6 +259,7 @@ bfa_status_t    bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
                               struct bfa_port_cfg_s *port_cfg);
 bfa_status_t    bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
 bfa_status_t    bfad_drv_init(struct bfad_s *bfad);
+bfa_status_t   bfad_start_ops(struct bfad_s *bfad);
 void            bfad_drv_start(struct bfad_s *bfad);
 void            bfad_uncfg_pport(struct bfad_s *bfad);
 void            bfad_drv_stop(struct bfad_s *bfad);
@@ -279,6 +281,7 @@ void                bfad_drv_uninit(struct bfad_s *bfad);
 void           bfad_drv_log_level_set(struct bfad_s *bfad);
 bfa_status_t   bfad_fc4_module_init(void);
 void           bfad_fc4_module_exit(void);
+int            bfad_worker (void *ptr);
 
 void bfad_pci_remove(struct pci_dev *pdev);
 int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
index f788c2a..f9fc67a 100644 (file)
@@ -43,11 +43,11 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
        struct bfad_s         *bfad = drv;
        struct bfad_itnim_data_s *itnim_data;
        struct bfad_itnim_s *itnim;
+       u8         host_status = DID_OK;
 
        switch (io_status) {
        case BFI_IOIM_STS_OK:
                bfa_trc(bfad, scsi_status);
-               cmnd->result = ScsiResult(DID_OK, scsi_status);
                scsi_set_resid(cmnd, 0);
 
                if (sns_len > 0) {
@@ -56,8 +56,18 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
                                sns_len = SCSI_SENSE_BUFFERSIZE;
                        memcpy(cmnd->sense_buffer, sns_info, sns_len);
                }
-               if (residue > 0)
+               if (residue > 0) {
+                       bfa_trc(bfad, residue);
                        scsi_set_resid(cmnd, residue);
+                       if (!sns_len && (scsi_status == SAM_STAT_GOOD) &&
+                               (scsi_bufflen(cmnd) - residue) <
+                                       cmnd->underflow) {
+                               bfa_trc(bfad, 0);
+                               host_status = DID_ERROR;
+                       }
+               }
+               cmnd->result = ScsiResult(host_status, scsi_status);
+
                break;
 
        case BFI_IOIM_STS_ABORTED:
@@ -167,17 +177,15 @@ bfad_im_info(struct Scsi_Host *shost)
        static char     bfa_buf[256];
        struct bfad_im_port_s *im_port =
                        (struct bfad_im_port_s *) shost->hostdata[0];
-       struct bfa_ioc_attr_s  ioc_attr;
        struct bfad_s         *bfad = im_port->bfad;
+       char model[BFA_ADAPTER_MODEL_NAME_LEN];
 
-       memset(&ioc_attr, 0, sizeof(ioc_attr));
-       bfa_get_attr(&bfad->bfa, &ioc_attr);
+       bfa_get_adapter_model(&bfad->bfa, model);
 
        memset(bfa_buf, 0, sizeof(bfa_buf));
        snprintf(bfa_buf, sizeof(bfa_buf),
-                "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s",
-                ioc_attr.adapter_attr.model, bfad->pci_name,
-                BFAD_DRIVER_VERSION);
+               "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s",
+               model, bfad->pci_name, BFAD_DRIVER_VERSION);
        return bfa_buf;
 }
 
@@ -501,16 +509,6 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
 }
 
 /**
- * Path TOV processing begin notification -- dummy for linux
- */
-void
-bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim)
-{
-}
-
-
-
-/**
  * Allocate a Scsi_Host for a port.
  */
 int
@@ -931,10 +929,9 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
        struct Scsi_Host *host = im_port->shost;
        struct bfad_s         *bfad = im_port->bfad;
        struct bfad_port_s    *port = im_port->port;
-       union attr {
-               struct bfa_pport_attr_s pattr;
-               struct bfa_ioc_attr_s  ioc_attr;
-       } attr;
+       struct bfa_pport_attr_s pattr;
+       char model[BFA_ADAPTER_MODEL_NAME_LEN];
+       char fw_ver[BFA_VERSION_LEN];
 
        fc_host_node_name(host) =
                bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
@@ -954,20 +951,18 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
        /* For fibre channel services type 0x20 */
        fc_host_supported_fc4s(host)[7] = 1;
 
-       memset(&attr.ioc_attr, 0, sizeof(attr.ioc_attr));
-       bfa_get_attr(&bfad->bfa, &attr.ioc_attr);
+       bfa_get_adapter_model(&bfad->bfa, model);
+       bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver);
        sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s",
-               attr.ioc_attr.adapter_attr.model,
-               attr.ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+               model, fw_ver, BFAD_DRIVER_VERSION);
 
        fc_host_supported_speeds(host) = 0;
        fc_host_supported_speeds(host) |=
                FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
                FC_PORTSPEED_1GBIT;
 
-       memset(&attr.pattr, 0, sizeof(attr.pattr));
-       bfa_pport_get_attr(&bfad->bfa, &attr.pattr);
-       fc_host_maxframe_size(host) = attr.pattr.pport_cfg.maxfrsize;
+       bfa_fcport_get_attr(&bfad->bfa, &pattr);
+       fc_host_maxframe_size(host) = pattr.pport_cfg.maxfrsize;
 }
 
 static void
index 189a5b2..85ab2da 100644 (file)
@@ -23,7 +23,6 @@
 
 #define FCPI_NAME " fcpim"
 
-void bfad_flags_set(struct bfad_s *bfad, u32 flags);
 bfa_status_t bfad_im_module_init(void);
 void bfad_im_module_exit(void);
 bfa_status_t bfad_im_probe(struct bfad_s *bfad);
@@ -126,7 +125,6 @@ bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad);
 void bfad_os_destroy_workq(struct bfad_im_s *im);
 void bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv);
 void bfad_os_fc_host_init(struct bfad_im_port_s *im_port);
-void bfad_os_init_work(struct bfad_im_port_s *im_port);
 void bfad_os_scsi_host_free(struct bfad_s *bfad,
                                 struct bfad_im_port_s *im_port);
 void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim,
@@ -136,9 +134,6 @@ struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id);
 int bfad_os_scsi_add_host(struct Scsi_Host *shost,
                struct bfad_im_port_s *im_port, struct bfad_s *bfad);
 
-/*
- * scsi_host_template entries
- */
 void bfad_im_itnim_unmap(struct bfad_im_port_s  *im_port,
                         struct bfad_itnim_s *itnim);
 
index 7de8832..2b7dbec 100644 (file)
@@ -23,8 +23,10 @@ BFA_TRC_FILE(LDRV, INTR);
 /**
  *  bfa_isr BFA driver interrupt functions
  */
-static int msix_disable;
-module_param(msix_disable, int, S_IRUGO | S_IWUSR);
+static int msix_disable_cb;
+static int msix_disable_ct;
+module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
+module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
 /**
  * Line based interrupt handler.
  */
@@ -141,6 +143,7 @@ bfad_setup_intr(struct bfad_s *bfad)
        int error = 0;
        u32 mask = 0, i, num_bit = 0, max_bit = 0;
        struct msix_entry msix_entries[MAX_MSIX_ENTRY];
+       struct pci_dev *pdev = bfad->pcidev;
 
        /* Call BFA to get the msix map for this PCI function.  */
        bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
@@ -148,7 +151,9 @@ bfad_setup_intr(struct bfad_s *bfad)
        /* Set up the msix entry table */
        bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
 
-       if (!msix_disable) {
+       if ((pdev->device == BFA_PCI_DEVICE_ID_CT && !msix_disable_ct) ||
+           (pdev->device != BFA_PCI_DEVICE_ID_CT && !msix_disable_cb)) {
+
                error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
                if (error) {
                        /*
index a4b5dd4..8166e97 100644 (file)
@@ -37,7 +37,7 @@ BFA_TRC_FILE(FCS, FABRIC);
 #define BFA_FCS_FABRIC_CLEANUP_DELAY   (10000) /* Milliseconds */
 
 #define bfa_fcs_fabric_set_opertype(__fabric) do {             \
-       if (bfa_pport_get_topology((__fabric)->fcs->bfa)       \
+       if (bfa_fcport_get_topology((__fabric)->fcs->bfa)       \
                                == BFA_PPORT_TOPOLOGY_P2P)     \
                (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT;  \
        else                                                   \
@@ -136,8 +136,7 @@ bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
        case BFA_FCS_FABRIC_SM_CREATE:
                bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created);
                bfa_fcs_fabric_init(fabric);
-               bfa_fcs_lport_init(&fabric->bport, fabric->fcs, FC_VF_ID_NULL,
-                                  &fabric->bport.port_cfg, NULL);
+               bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg);
                break;
 
        case BFA_FCS_FABRIC_SM_LINK_UP:
@@ -161,7 +160,7 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
 
        switch (event) {
        case BFA_FCS_FABRIC_SM_START:
-               if (bfa_pport_is_linkup(fabric->fcs->bfa)) {
+               if (bfa_fcport_is_linkup(fabric->fcs->bfa)) {
                        bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
                        bfa_fcs_fabric_login(fabric);
                } else
@@ -225,7 +224,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
        switch (event) {
        case BFA_FCS_FABRIC_SM_CONT_OP:
 
-               bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+               bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
                fabric->fab_type = BFA_FCS_FABRIC_SWITCHED;
 
                if (fabric->auth_reqd && fabric->is_auth) {
@@ -252,7 +251,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
 
        case BFA_FCS_FABRIC_SM_NO_FABRIC:
                fabric->fab_type = BFA_FCS_FABRIC_N2N;
-               bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+               bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
                bfa_fcs_fabric_notify_online(fabric);
                bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric);
                break;
@@ -419,7 +418,7 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
 
        case BFA_FCS_FABRIC_SM_NO_FABRIC:
                bfa_trc(fabric->fcs, fabric->bb_credit);
-               bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+               bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
                break;
 
        default:
@@ -563,17 +562,15 @@ void
 bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
 {
        struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
-       struct bfa_adapter_attr_s adapter_attr;
+       char            model[BFA_ADAPTER_MODEL_NAME_LEN] = {0};
        struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info;
 
-       bfa_os_memset((void *)&adapter_attr, 0,
-                     sizeof(struct bfa_adapter_attr_s));
-       bfa_ioc_get_adapter_attr(&fabric->fcs->bfa->ioc, &adapter_attr);
+       bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
 
        /*
         * Model name/number
         */
-       strncpy((char *)&port_cfg->sym_name, adapter_attr.model,
+       strncpy((char *)&port_cfg->sym_name, model,
                BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
        strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
                sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
@@ -719,10 +716,10 @@ bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric)
        struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg;
        u8         alpa = 0;
 
-       if (bfa_pport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP)
-               alpa = bfa_pport_get_myalpa(bfa);
+       if (bfa_fcport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP)
+               alpa = bfa_fcport_get_myalpa(bfa);
 
-       bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_pport_get_maxfrsize(bfa),
+       bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa),
                      pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd);
 
        fabric->stats.flogi_sent++;
@@ -814,10 +811,10 @@ bfa_fcs_fabric_delete_comp(void *cbarg)
  */
 
 /**
- *   Module initialization
+ *   Attach time initialization
  */
 void
-bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
+bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
 {
        struct bfa_fcs_fabric_s *fabric;
 
@@ -841,7 +838,13 @@ bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
        bfa_wc_up(&fabric->wc); /* For the base port */
 
        bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
-       bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CREATE);
+       bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL);
+}
+
+void
+bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
+{
+       bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE);
        bfa_trc(fcs, 0);
 }
 
@@ -890,6 +893,12 @@ bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
        return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback);
 }
 
+bfa_boolean_t
+bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric)
+{
+       return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_auth_failed);
+}
+
 enum bfa_pport_type
 bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
 {
@@ -1165,8 +1174,8 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
        reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
                                    bfa_os_hton3b(FC_FABRIC_PORT),
                                    n2n_port->reply_oxid, pcfg->pwwn,
-                                   pcfg->nwwn, bfa_pport_get_maxfrsize(bfa),
-                                   bfa_pport_get_rx_bbcredit(bfa));
+                                   pcfg->nwwn, bfa_fcport_get_maxfrsize(bfa),
+                                   bfa_fcport_get_rx_bbcredit(bfa));
 
        bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps),
                        BFA_FALSE, FC_CLASS_3, reqlen, &fchs,
@@ -1224,14 +1233,8 @@ bfa_fcs_fabric_aen_post(struct bfa_fcs_port_s *port,
        wwn2str(pwwn_ptr, pwwn);
        wwn2str(fwwn_ptr, fwwn);
 
-       switch (event) {
-       case BFA_PORT_AEN_FABRIC_NAME_CHANGE:
-               bfa_log(logmod, BFA_AEN_PORT_FABRIC_NAME_CHANGE, pwwn_ptr,
-                       fwwn_ptr);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, event),
+               pwwn_ptr, fwwn_ptr);
 
        aen_data.port.pwwn = pwwn;
        aen_data.port.fwwn = fwwn;
index 8fa7f27..981d98d 100644 (file)
@@ -72,6 +72,9 @@ fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed_s speed)
        case RPSC_OP_SPEED_8G:
                return BFA_PPORT_SPEED_8GBPS;
 
+       case RPSC_OP_SPEED_10G:
+               return BFA_PPORT_SPEED_10GBPS;
+
        default:
                return BFA_PPORT_SPEED_UNKNOWN;
        }
@@ -97,6 +100,9 @@ fc_bfa_speed_to_rpsc_operspeed(enum bfa_pport_speed op_speed)
        case BFA_PPORT_SPEED_8GBPS:
                return RPSC_OP_SPEED_8G;
 
+       case BFA_PPORT_SPEED_10GBPS:
+               return RPSC_OP_SPEED_10G;
+
        default:
                return RPSC_OP_SPEED_NOT_EST;
        }
index 1f3c06e..8ae4a2c 100644 (file)
@@ -126,7 +126,7 @@ bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 
 }
@@ -161,7 +161,7 @@ bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -205,7 +205,7 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -240,7 +240,7 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -270,7 +270,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -298,7 +298,7 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -321,7 +321,7 @@ bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -354,7 +354,7 @@ bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(itnim->fcs, event);
        }
 }
 
@@ -385,19 +385,8 @@ bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
        wwn2str(lpwwn_ptr, lpwwn);
        wwn2str(rpwwn_ptr, rpwwn);
 
-       switch (event) {
-       case BFA_ITNIM_AEN_ONLINE:
-               bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr);
-               break;
-       case BFA_ITNIM_AEN_OFFLINE:
-               bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr);
-               break;
-       case BFA_ITNIM_AEN_DISCONNECT:
-               bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, event),
+               rpwwn_ptr, lpwwn_ptr);
 
        aen_data.itnim.vf_id = rport->port->fabric->vf_id;
        aen_data.itnim.ppwwn =
@@ -689,7 +678,6 @@ bfa_cb_itnim_tov_begin(void *cb_arg)
        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
 
        bfa_trc(itnim->fcs, itnim->rport->pwwn);
-       bfa_fcb_itnim_tov_begin(itnim->itnim_drv);
 }
 
 /**
@@ -822,22 +810,3 @@ void
 bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim)
 {
 }
-
-/**
- *   Module initialization
- */
-void
-bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs)
-{
-}
-
-/**
- *   Module cleanup
- */
-void
-bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs)
-{
-       bfa_fcs_modexit_comp(fcs);
-}
-
-
index eee9608..244c3f0 100644 (file)
@@ -29,6 +29,7 @@
 /*
 * fcs friend functions: only between fcs modules
  */
+void           bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs);
 void            bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
 void            bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
 void            bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs);
@@ -46,6 +47,7 @@ void            bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric,
                        struct fchs_s *fchs, u16 len);
 u16        bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
 bfa_boolean_t   bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric);
+bfa_boolean_t  bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric);
 enum bfa_pport_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric);
 void           bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric);
 void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric);
index 61e9e26..11e6e7b 100644 (file)
@@ -34,11 +34,6 @@ void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim);
 void bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim);
 void bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim);
 
-/*
- * Modudle init/cleanup routines.
- */
-void bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs);
 void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
                        u16 len);
 #endif /* __FCS_FCPIM_H__ */
index ae744ba..a6508c8 100644 (file)
@@ -84,9 +84,10 @@ void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
  * Following routines will be called by Fabric to indicate port
  * online/offline to vport.
  */
-void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
-                       u16 vf_id, struct bfa_port_cfg_s *port_cfg,
-                       struct bfa_fcs_vport_s *vport);
+void bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
+                       uint16_t vf_id, struct bfa_fcs_vport_s *vport);
+void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport,
+                       struct bfa_port_cfg_s *port_cfg);
 void bfa_fcs_port_online(struct bfa_fcs_port_s *port);
 void bfa_fcs_port_offline(struct bfa_fcs_port_s *port);
 void bfa_fcs_port_delete(struct bfa_fcs_port_s *port);
index abb6519..408c06a 100644 (file)
@@ -26,7 +26,6 @@
 /*
  * fcs friend functions: only between fcs modules
  */
-void bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_pport_attach(struct bfa_fcs_s *fcs);
 
 #endif /* __FCS_PPORT_H__ */
index f601e9d..9c8d1d2 100644 (file)
@@ -24,9 +24,6 @@
 
 #include <fcs/bfa_fcs_rport.h>
 
-void bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs);
-
 void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
                        u16 len);
 void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
index 96f1bdc..f591072 100644 (file)
@@ -26,7 +26,6 @@
 /*
  * fcs friend functions: only between fcs modules
  */
-void bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
 
 #endif /* __FCS_UF_H__ */
index 9e80b6a..13c32eb 100644 (file)
 #include <fcs/bfa_fcs_vport.h>
 #include <defs/bfa_defs_pci.h>
 
-/*
- * Modudle init/cleanup routines.
- */
-
-void bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs);
-
 void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
 void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport);
 void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
 void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
-u32 bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs);
 
 #endif /* __FCS_VPORT_H__ */
 
index df2a1e5..8f17076 100644 (file)
@@ -116,6 +116,9 @@ static void     bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
                        enum port_fdmi_event event);
 static void     bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
                        enum port_fdmi_event event);
+static void    bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi,
+                       enum port_fdmi_event event);
+
 /**
  *             Start in offline state - awaiting MS to send start.
  */
@@ -155,7 +158,7 @@ bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -180,7 +183,7 @@ bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -227,7 +230,7 @@ bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -255,7 +258,7 @@ bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -283,7 +286,7 @@ bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -328,7 +331,7 @@ bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -356,7 +359,7 @@ bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -384,7 +387,7 @@ bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -428,7 +431,7 @@ bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -456,7 +459,7 @@ bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
@@ -475,10 +478,24 @@ bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(port->fcs, event);
        }
 }
 
+/**
+ *  FDMI is disabled state.
+ */
+static void
+bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi,
+                               enum port_fdmi_event event)
+{
+       struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+       bfa_trc(port->fcs, port->port_cfg.pwwn);
+       bfa_trc(port->fcs, event);
+
+       /* No op State. It can only be enabled at Driver Init. */
+}
 
 /**
 *   RHBA : Register HBA Attributes.
@@ -1097,36 +1114,23 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
 {
        struct bfa_fcs_port_s *port = fdmi->ms->port;
        struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
-       struct bfa_adapter_attr_s adapter_attr;
 
        bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
-       bfa_os_memset(&adapter_attr, 0, sizeof(struct bfa_adapter_attr_s));
-
-       bfa_ioc_get_adapter_attr(&port->fcs->bfa->ioc, &adapter_attr);
-
-       strncpy(hba_attr->manufacturer, adapter_attr.manufacturer,
-               sizeof(adapter_attr.manufacturer));
-
-       strncpy(hba_attr->serial_num, adapter_attr.serial_num,
-               sizeof(adapter_attr.serial_num));
 
-       strncpy(hba_attr->model, adapter_attr.model, sizeof(hba_attr->model));
-
-       strncpy(hba_attr->model_desc, adapter_attr.model_descr,
-               sizeof(hba_attr->model_desc));
-
-       strncpy(hba_attr->hw_version, adapter_attr.hw_ver,
-               sizeof(hba_attr->hw_version));
+       bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc,
+               hba_attr->manufacturer);
+       bfa_ioc_get_adapter_serial_num(&port->fcs->bfa->ioc,
+                                               hba_attr->serial_num);
+       bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, hba_attr->model);
+       bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, hba_attr->model_desc);
+       bfa_ioc_get_pci_chip_rev(&port->fcs->bfa->ioc, hba_attr->hw_version);
+       bfa_ioc_get_adapter_optrom_ver(&port->fcs->bfa->ioc,
+               hba_attr->option_rom_ver);
+       bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc, hba_attr->fw_version);
 
        strncpy(hba_attr->driver_version, (char *)driver_info->version,
                sizeof(hba_attr->driver_version));
 
-       strncpy(hba_attr->option_rom_ver, adapter_attr.optrom_ver,
-               sizeof(hba_attr->option_rom_ver));
-
-       strncpy(hba_attr->fw_version, adapter_attr.fw_ver,
-               sizeof(hba_attr->fw_version));
-
        strncpy(hba_attr->os_name, driver_info->host_os_name,
                sizeof(hba_attr->os_name));
 
@@ -1158,7 +1162,7 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
        /*
         * get pport attributes from hal
         */
-       bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+       bfa_fcport_get_attr(port->fcs->bfa, &pport_attr);
 
        /*
         * get FC4 type Bitmask
@@ -1201,7 +1205,10 @@ bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms)
        struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
 
        fdmi->ms = ms;
-       bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+       if (ms->port->fcs->fdmi_enabled)
+               bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+       else
+               bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_disabled);
 }
 
 void
index d9cbc2a..6abbab0 100644 (file)
 #define __BFA_AEN_H__
 
 #include "defs/bfa_defs_aen.h"
+#include "defs/bfa_defs_status.h"
+#include "cs/bfa_debug.h"
 
-#define BFA_AEN_MAX_ENTRY   512
+#define BFA_AEN_MAX_ENTRY      512
 
-extern s32 bfa_aen_max_cfg_entry;
+extern int bfa_aen_max_cfg_entry;
 struct bfa_aen_s {
        void            *bfad;
-       s32             max_entry;
-       s32             write_index;
-       s32             read_index;
-       u32     bfad_num;
-       u32     seq_num;
+       int             max_entry;
+       int             write_index;
+       int             read_index;
+       int             bfad_num;
+       int             seq_num;
        void            (*aen_cb_notify)(void *bfad);
        void            (*gettimeofday)(struct bfa_timeval_s *tv);
-       struct bfa_trc_mod_s    *trcmod;
-       struct bfa_aen_entry_s  list[BFA_AEN_MAX_ENTRY]; /* Must be the last */
+       struct bfa_trc_mod_s *trcmod;
+       int             app_ri[BFA_AEN_MAX_APP]; /* For multiclient support */
+       struct bfa_aen_entry_s list[BFA_AEN_MAX_ENTRY]; /* Must be the last */
 };
 
 
@@ -45,48 +48,49 @@ bfa_aen_set_max_cfg_entry(int max_entry)
        bfa_aen_max_cfg_entry = max_entry;
 }
 
-static inline s32
+static inline int
 bfa_aen_get_max_cfg_entry(void)
 {
        return bfa_aen_max_cfg_entry;
 }
 
-static inline s32
+static inline int
 bfa_aen_get_meminfo(void)
 {
        return sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry();
 }
 
-static inline s32
+static inline int
 bfa_aen_get_wi(struct bfa_aen_s *aen)
 {
        return aen->write_index;
 }
 
-static inline s32
+static inline int
 bfa_aen_get_ri(struct bfa_aen_s *aen)
 {
        return aen->read_index;
 }
 
-static inline s32
-bfa_aen_fetch_count(struct bfa_aen_s *aen, s32 read_index)
+static inline int
+bfa_aen_fetch_count(struct bfa_aen_s *aen, enum bfa_aen_app  app_id)
 {
-       return ((aen->write_index + aen->max_entry) - read_index)
+       bfa_assert((app_id < BFA_AEN_MAX_APP) && (app_id >= bfa_aen_app_bcu));
+       return ((aen->write_index + aen->max_entry) - aen->app_ri[app_id])
                % aen->max_entry;
 }
 
-s32 bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod,
-               void *bfad, u32 inst_id, void (*aen_cb_notify)(void *),
+int bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod,
+               void *bfad, int bfad_num, void (*aen_cb_notify)(void *),
                void (*gettimeofday)(struct bfa_timeval_s *));
 
-s32 bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category,
+void bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category,
                     int aen_type, union bfa_aen_data_u *aen_data);
 
-s32 bfa_aen_fetch(struct bfa_aen_s *aen, struct bfa_aen_entry_s *aen_entry,
-                     s32 entry_space, s32 rii, s32 *ri_arr,
-                     s32 ri_arr_cnt);
+bfa_status_t bfa_aen_fetch(struct bfa_aen_s *aen,
+                       struct bfa_aen_entry_s *aen_entry,
+                       int entry_req, enum bfa_aen_app app_id, int *entry_ret);
 
-s32 bfa_aen_get_inst(struct bfa_aen_s *aen);
+int bfa_aen_get_inst(struct bfa_aen_s *aen);
 
 #endif /* __BFA_AEN_H__ */
index d4bc0d9..1f5966c 100644 (file)
@@ -106,6 +106,26 @@ struct bfa_sge_s {
        bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats)
 #define bfa_ioc_clear_stats(__bfa)     \
        bfa_ioc_clr_stats(&(__bfa)->ioc)
+#define bfa_get_nports(__bfa)   \
+       bfa_ioc_get_nports(&(__bfa)->ioc)
+#define bfa_get_adapter_manufacturer(__bfa, __manufacturer) \
+       bfa_ioc_get_adapter_manufacturer(&(__bfa)->ioc, __manufacturer)
+#define bfa_get_adapter_model(__bfa, __model)   \
+       bfa_ioc_get_adapter_model(&(__bfa)->ioc, __model)
+#define bfa_get_adapter_serial_num(__bfa, __serial_num) \
+       bfa_ioc_get_adapter_serial_num(&(__bfa)->ioc, __serial_num)
+#define bfa_get_adapter_fw_ver(__bfa, __fw_ver) \
+       bfa_ioc_get_adapter_fw_ver(&(__bfa)->ioc, __fw_ver)
+#define bfa_get_adapter_optrom_ver(__bfa, __optrom_ver) \
+       bfa_ioc_get_adapter_optrom_ver(&(__bfa)->ioc, __optrom_ver)
+#define bfa_get_pci_chip_rev(__bfa, __chip_rev) \
+       bfa_ioc_get_pci_chip_rev(&(__bfa)->ioc, __chip_rev)
+#define bfa_get_ioc_state(__bfa)    \
+       bfa_ioc_get_state(&(__bfa)->ioc)
+#define bfa_get_type(__bfa) \
+       bfa_ioc_get_type(&(__bfa)->ioc)
+#define bfa_get_mac(__bfa)  \
+       bfa_ioc_get_mac(&(__bfa)->ioc)
 
 /*
  * bfa API functions
@@ -161,6 +181,7 @@ bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
 void bfa_iocfc_enable(struct bfa_s *bfa);
 void bfa_iocfc_disable(struct bfa_s *bfa);
 void bfa_ioc_auto_recover(bfa_boolean_t auto_recover);
+void bfa_chip_reset(struct bfa_s *bfa);
 void bfa_cb_ioc_disable(void *bfad);
 void bfa_timer_tick(struct bfa_s *bfa);
 #define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)        \
@@ -171,6 +192,7 @@ void bfa_timer_tick(struct bfa_s *bfa);
  */
 bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen);
 bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen);
+void bfa_debug_fwsave_clear(struct bfa_s *bfa);
 
 #include "bfa_priv.h"
 
index 268d956..1349b99 100644 (file)
@@ -26,6 +26,7 @@ struct bfa_fcxp_s;
 #include <defs/bfa_defs_pport.h>
 #include <defs/bfa_defs_rport.h>
 #include <defs/bfa_defs_qos.h>
+#include <defs/bfa_defs_fcport.h>
 #include <cs/bfa_sm.h>
 #include <bfa.h>
 
@@ -35,7 +36,7 @@ struct bfa_fcxp_s;
 struct bfa_rport_info_s {
        u16        max_frmsz;   /*  max rcv pdu size               */
        u32        pid:24,              /*  remote port ID                 */
-                       lp_tag:8;
+                       lp_tag:8;       /*  tag                     */
        u32        local_pid:24,        /*  local port ID                   */
                        cisc:8;         /*  CIRO supported                  */
        u8         fc_class;    /*  supported FC classes. enum fc_cos */
@@ -54,7 +55,7 @@ struct bfa_rport_s {
        void                  *rport_drv; /*  fcs/driver rport object */
        u16              fw_handle; /*  firmware rport handle */
        u16              rport_tag; /*  BFA rport tag */
-       struct bfa_rport_info_s rport_info; /*  rport info from *fcs/driver */
+       struct bfa_rport_info_s rport_info; /*  rport info from fcs/driver */
        struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq */
        struct bfa_cb_qe_s    hcb_qe;    /*  BFA callback qelem */
        struct bfa_rport_hal_stats_s stats; /*  BFA rport statistics  */
@@ -101,7 +102,7 @@ struct bfa_uf_buf_s {
 struct bfa_uf_s {
        struct list_head        qe;             /*  queue element         */
        struct bfa_s    *bfa;           /*  bfa instance          */
-       u16        uf_tag;              /*  identifying tag f/w messages */
+       u16        uf_tag;              /*  identifying tag fw msgs     */
        u16        vf_id;
        u16        src_rport_handle;
        u16        rsvd;
@@ -127,7 +128,7 @@ struct bfa_lps_s {
        u8              reqq;           /*  lport request queue */
        u8              alpa;           /*  ALPA for loop topologies    */
        u32     lp_pid;         /*  lport port ID               */
-       bfa_boolean_t   fdisc;          /*  send FDISC instead of FLOGI*/
+       bfa_boolean_t   fdisc;          /*  send FDISC instead of FLOGI  */
        bfa_boolean_t   auth_en;        /*  enable authentication       */
        bfa_boolean_t   auth_req;       /*  authentication required     */
        bfa_boolean_t   npiv_en;        /*  NPIV is allowed by peer     */
@@ -151,60 +152,69 @@ struct bfa_lps_s {
        bfa_eproto_status_t     ext_status;
 };
 
+#define BFA_FCPORT(_bfa)        (&((_bfa)->modules.port))
+
 /*
  * bfa pport API functions
  */
-bfa_status_t bfa_pport_enable(struct bfa_s *bfa);
-bfa_status_t bfa_pport_disable(struct bfa_s *bfa);
-bfa_status_t bfa_pport_cfg_speed(struct bfa_s *bfa,
+bfa_status_t bfa_fcport_enable(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_disable(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_cfg_speed(struct bfa_s *bfa,
                        enum bfa_pport_speed speed);
-enum bfa_pport_speed bfa_pport_get_speed(struct bfa_s *bfa);
-bfa_status_t bfa_pport_cfg_topology(struct bfa_s *bfa,
+enum bfa_pport_speed bfa_fcport_get_speed(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa,
                        enum bfa_pport_topology topo);
-enum bfa_pport_topology bfa_pport_get_topology(struct bfa_s *bfa);
-bfa_status_t bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa);
-bfa_boolean_t bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa);
-u8 bfa_pport_get_myalpa(struct bfa_s *bfa);
-bfa_status_t bfa_pport_clr_hardalpa(struct bfa_s *bfa);
-bfa_status_t bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize);
-u16 bfa_pport_get_maxfrsize(struct bfa_s *bfa);
-u32 bfa_pport_mypid(struct bfa_s *bfa);
-u8 bfa_pport_get_rx_bbcredit(struct bfa_s *bfa);
-bfa_status_t bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap);
-bfa_status_t bfa_pport_trunk_disable(struct bfa_s *bfa);
-bfa_boolean_t bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap);
-void bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr);
-wwn_t bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node);
-bfa_status_t bfa_pport_get_stats(struct bfa_s *bfa,
-                       union bfa_pport_stats_u *stats,
-                       bfa_cb_pport_t cbfn, void *cbarg);
-bfa_status_t bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
-                       void *cbarg);
-void bfa_pport_event_register(struct bfa_s *bfa,
+enum bfa_pport_topology bfa_fcport_get_topology(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa);
+bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa);
+u8 bfa_fcport_get_myalpa(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_clr_hardalpa(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize);
+u16 bfa_fcport_get_maxfrsize(struct bfa_s *bfa);
+u32 bfa_fcport_mypid(struct bfa_s *bfa);
+u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_trunk_enable(struct bfa_s *bfa, u8 bitmap);
+bfa_status_t bfa_fcport_trunk_disable(struct bfa_s *bfa);
+bfa_boolean_t bfa_fcport_trunk_query(struct bfa_s *bfa, u32 *bitmap);
+void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr);
+wwn_t bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node);
+void bfa_fcport_event_register(struct bfa_s *bfa,
                        void (*event_cbfn) (void *cbarg,
                        bfa_pport_event_t event), void *event_cbarg);
-bfa_boolean_t bfa_pport_is_disabled(struct bfa_s *bfa);
-void bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
-void bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
-bfa_status_t bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa,
+bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa);
+void bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
+void bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
+bfa_status_t bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa,
                        enum bfa_pport_speed speed);
-enum bfa_pport_speed bfa_pport_get_ratelim_speed(struct bfa_s *bfa);
+enum bfa_pport_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa);
 
-void bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
-void bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status);
-void bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
+void bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status);
+void bfa_fcport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
                        bfa_boolean_t link_e2e_beacon);
 void bfa_cb_pport_event(void *cbarg, bfa_pport_event_t event);
-void bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr);
-void bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+void bfa_fcport_qos_get_attr(struct bfa_s *bfa,
+                       struct bfa_qos_attr_s *qos_attr);
+void bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
                        struct bfa_qos_vc_attr_s *qos_vc_attr);
-bfa_status_t bfa_pport_get_qos_stats(struct bfa_s *bfa,
-                       union bfa_pport_stats_u *stats,
+bfa_status_t bfa_fcport_get_qos_stats(struct bfa_s *bfa,
+                       union bfa_fcport_stats_u *stats,
                        bfa_cb_pport_t cbfn, void *cbarg);
-bfa_status_t bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+bfa_status_t bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
                        void *cbarg);
-bfa_boolean_t     bfa_pport_is_ratelim(struct bfa_s *bfa);
-bfa_boolean_t  bfa_pport_is_linkup(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_get_fcoe_stats(struct bfa_s *bfa,
+                       union bfa_fcport_stats_u *stats,
+                       bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+                       void *cbarg);
+
+bfa_boolean_t     bfa_fcport_is_ratelim(struct bfa_s *bfa);
+bfa_boolean_t  bfa_fcport_is_linkup(struct bfa_s *bfa);
+bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
+               union bfa_fcport_stats_u *stats,
+               bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+               void *cbarg);
 
 /*
  * bfa rport API functions
@@ -293,6 +303,7 @@ void bfa_uf_free(struct bfa_uf_s *uf);
  * bfa lport service api
  */
 
+u32    bfa_lps_get_max_vport(struct bfa_s *bfa);
 struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa);
 void bfa_lps_delete(struct bfa_lps_s *lps);
 void bfa_lps_discard(struct bfa_lps_s *lps);
@@ -315,10 +326,12 @@ wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps);
 wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps);
 u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps);
 u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps);
+mac_t bfa_lps_get_lp_mac(struct bfa_lps_s *lps);
 void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
 void bfa_cb_lps_flogo_comp(void *bfad, void *uarg);
 void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
 void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
+void bfa_cb_lps_cvl_event(void *bfad, void *uarg);
 
 #endif /* __BFA_SVC_H__ */
 
index e407103..f710874 100644 (file)
@@ -41,7 +41,7 @@ struct bfa_timer_mod_s {
        struct list_head timer_q;
 };
 
-#define BFA_TIMER_FREQ 500 /**< specified in millisecs */
+#define BFA_TIMER_FREQ 200 /**< specified in millisecs */
 
 void bfa_timer_beat(struct bfa_timer_mod_s *mod);
 void bfa_timer_init(struct bfa_timer_mod_s *mod);
index 7042c18..a550e80 100644 (file)
@@ -143,8 +143,8 @@ enum bfi_mclass {
        BFI_MC_IOC              = 1,    /*  IO Controller (IOC)     */
        BFI_MC_DIAG             = 2,    /*  Diagnostic Msgs                 */
        BFI_MC_FLASH            = 3,    /*  Flash message class     */
-       BFI_MC_CEE              = 4,
-       BFI_MC_FC_PORT          = 5,    /*  FC port                         */
+       BFI_MC_CEE              = 4,    /*  CEE                     */
+       BFI_MC_FCPORT           = 5,    /*  FC port                         */
        BFI_MC_IOCFC            = 6,    /*  FC - IO Controller (IOC)        */
        BFI_MC_LL               = 7,    /*  Link Layer                      */
        BFI_MC_UF               = 8,    /*  Unsolicited frame receive       */
index b3bb52b..a51ee61 100644 (file)
 #define __PSS_LMEM_INIT_EN               0x00000100
 #define __PSS_LPU1_RESET                 0x00000002
 #define __PSS_LPU0_RESET                 0x00000001
-
+#define PSS_ERR_STATUS_REG              0x00018810
+#define __PSS_LMEM1_CORR_ERR            0x00000800
+#define __PSS_LMEM0_CORR_ERR             0x00000400
+#define __PSS_LMEM1_UNCORR_ERR           0x00000200
+#define __PSS_LMEM0_UNCORR_ERR           0x00000100
+#define __PSS_BAL_PERR                   0x00000080
+#define __PSS_DIP_IF_ERR                 0x00000040
+#define __PSS_IOH_IF_ERR                 0x00000020
+#define __PSS_TDS_IF_ERR                 0x00000010
+#define __PSS_RDS_IF_ERR                 0x00000008
+#define __PSS_SGM_IF_ERR                 0x00000004
+#define __PSS_LPU1_RAM_ERR               0x00000002
+#define __PSS_LPU0_RAM_ERR               0x00000001
+#define ERR_SET_REG                     0x00018818
+#define __PSS_ERR_STATUS_SET            0x00000fff
 
 /*
  * These definitions are either in error/missing in spec. Its auto-generated
index d3caa58..57a8497 100644 (file)
@@ -430,6 +430,31 @@ enum {
 #define __PSS_LMEM_INIT_EN               0x00000100
 #define __PSS_LPU1_RESET                 0x00000002
 #define __PSS_LPU0_RESET                 0x00000001
+#define PSS_ERR_STATUS_REG               0x00018810
+#define __PSS_LPU1_TCM_READ_ERR          0x00200000
+#define __PSS_LPU0_TCM_READ_ERR          0x00100000
+#define __PSS_LMEM5_CORR_ERR             0x00080000
+#define __PSS_LMEM4_CORR_ERR             0x00040000
+#define __PSS_LMEM3_CORR_ERR             0x00020000
+#define __PSS_LMEM2_CORR_ERR             0x00010000
+#define __PSS_LMEM1_CORR_ERR             0x00008000
+#define __PSS_LMEM0_CORR_ERR             0x00004000
+#define __PSS_LMEM5_UNCORR_ERR           0x00002000
+#define __PSS_LMEM4_UNCORR_ERR           0x00001000
+#define __PSS_LMEM3_UNCORR_ERR           0x00000800
+#define __PSS_LMEM2_UNCORR_ERR           0x00000400
+#define __PSS_LMEM1_UNCORR_ERR           0x00000200
+#define __PSS_LMEM0_UNCORR_ERR           0x00000100
+#define __PSS_BAL_PERR                   0x00000080
+#define __PSS_DIP_IF_ERR                 0x00000040
+#define __PSS_IOH_IF_ERR                 0x00000020
+#define __PSS_TDS_IF_ERR                 0x00000010
+#define __PSS_RDS_IF_ERR                 0x00000008
+#define __PSS_SGM_IF_ERR                 0x00000004
+#define __PSS_LPU1_RAM_ERR               0x00000002
+#define __PSS_LPU0_RAM_ERR               0x00000001
+#define ERR_SET_REG                     0x00018818
+#define __PSS_ERR_STATUS_SET            0x003fffff
 #define HQM_QSET0_RXQ_DRBL_P0            0x00038000
 #define __RXQ0_ADD_VECTORS_P             0x80000000
 #define __RXQ0_STOP_P                    0x40000000
@@ -589,6 +614,7 @@ enum {
 #define __HFN_INT_MBOX_LPU1                0x00200000U
 #define __HFN_INT_MBOX1_LPU0               0x00400000U
 #define __HFN_INT_MBOX1_LPU1               0x00800000U
+#define __HFN_INT_LL_HALT                 0x01000000U
 #define __HFN_INT_CPE_MASK                 0x000000ffU
 #define __HFN_INT_RME_MASK                 0x0000ff00U
 
index 96ef056..a0158aa 100644 (file)
@@ -123,7 +123,7 @@ enum bfi_ioc_state {
        BFI_IOC_DISABLING        = 5,   /*  IOC is being disabled           */
        BFI_IOC_DISABLED         = 6,   /*  IOC is disabled                 */
        BFI_IOC_CFG_DISABLED = 7,       /*  IOC is being disabled;transient */
-       BFI_IOC_HBFAIL       = 8,       /*  IOC heart-beat failure          */
+       BFI_IOC_FAIL       = 8,         /*  IOC heart-beat failure          */
        BFI_IOC_MEMTEST      = 9,       /*  IOC is doing memtest            */
 };
 
index c59d47b..7ed31bb 100644 (file)
@@ -30,6 +30,7 @@ enum bfi_lps_h2i_msgs {
 enum bfi_lps_i2h_msgs {
        BFI_LPS_H2I_LOGIN_RSP   = BFA_I2HM(1),
        BFI_LPS_H2I_LOGOUT_RSP  = BFA_I2HM(2),
+       BFI_LPS_H2I_CVL_EVENT   = BFA_I2HM(3),
 };
 
 struct bfi_lps_login_req_s {
@@ -77,6 +78,12 @@ struct bfi_lps_logout_rsp_s {
        u8              rsvd[2];
 };
 
+struct bfi_lps_cvl_event_s {
+       struct bfi_mhdr_s  mh;      /* common msg header      */
+       u8              lp_tag;
+       u8              rsvd[3];
+};
+
 union bfi_lps_h2i_msg_u {
        struct bfi_mhdr_s               *msg;
        struct bfi_lps_login_req_s      *login_req;
@@ -87,6 +94,7 @@ union bfi_lps_i2h_msg_u {
        struct bfi_msg_s                *msg;
        struct bfi_lps_login_rsp_s      *login_rsp;
        struct bfi_lps_logout_rsp_s     *logout_rsp;
+       struct bfi_lps_cvl_event_s      *cvl_event;
 };
 
 #pragma pack()
index c96d246..50dcf45 100644 (file)
 
 #pragma pack(1)
 
-enum bfi_pport_h2i {
-       BFI_PPORT_H2I_ENABLE_REQ                = (1),
-       BFI_PPORT_H2I_DISABLE_REQ               = (2),
-       BFI_PPORT_H2I_GET_STATS_REQ             = (3),
-       BFI_PPORT_H2I_CLEAR_STATS_REQ   = (4),
-       BFI_PPORT_H2I_SET_SVC_PARAMS_REQ        = (5),
-       BFI_PPORT_H2I_ENABLE_RX_VF_TAG_REQ      = (6),
-       BFI_PPORT_H2I_ENABLE_TX_VF_TAG_REQ      = (7),
-       BFI_PPORT_H2I_GET_QOS_STATS_REQ         = (8),
-       BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ       = (9),
+enum bfi_fcport_h2i {
+       BFI_FCPORT_H2I_ENABLE_REQ               = (1),
+       BFI_FCPORT_H2I_DISABLE_REQ              = (2),
+       BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ       = (3),
+       BFI_FCPORT_H2I_STATS_GET_REQ            = (4),
+       BFI_FCPORT_H2I_STATS_CLEAR_REQ          = (5),
 };
 
-enum bfi_pport_i2h {
-       BFI_PPORT_I2H_ENABLE_RSP                = BFA_I2HM(1),
-       BFI_PPORT_I2H_DISABLE_RSP               = BFA_I2HM(2),
-       BFI_PPORT_I2H_GET_STATS_RSP             = BFA_I2HM(3),
-       BFI_PPORT_I2H_CLEAR_STATS_RSP   = BFA_I2HM(4),
-       BFI_PPORT_I2H_SET_SVC_PARAMS_RSP        = BFA_I2HM(5),
-       BFI_PPORT_I2H_ENABLE_RX_VF_TAG_RSP      = BFA_I2HM(6),
-       BFI_PPORT_I2H_ENABLE_TX_VF_TAG_RSP      = BFA_I2HM(7),
-       BFI_PPORT_I2H_EVENT                     = BFA_I2HM(8),
-       BFI_PPORT_I2H_GET_QOS_STATS_RSP         = BFA_I2HM(9),
-       BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP       = BFA_I2HM(10),
+enum bfi_fcport_i2h {
+       BFI_FCPORT_I2H_ENABLE_RSP               = BFA_I2HM(1),
+       BFI_FCPORT_I2H_DISABLE_RSP              = BFA_I2HM(2),
+       BFI_FCPORT_I2H_SET_SVC_PARAMS_RSP       = BFA_I2HM(3),
+       BFI_FCPORT_I2H_STATS_GET_RSP            = BFA_I2HM(4),
+       BFI_FCPORT_I2H_STATS_CLEAR_RSP          = BFA_I2HM(5),
+       BFI_FCPORT_I2H_EVENT                    = BFA_I2HM(6),
 };
 
 /**
  * Generic REQ type
  */
-struct bfi_pport_generic_req_s {
+struct bfi_fcport_req_s {
        struct bfi_mhdr_s  mh;          /*  msg header                      */
-       u32        msgtag;              /*  msgtag for reply                */
+       u32        msgtag;      /*  msgtag for reply                */
 };
 
 /**
  * Generic RSP type
  */
-struct bfi_pport_generic_rsp_s {
+struct bfi_fcport_rsp_s {
        struct bfi_mhdr_s  mh;          /*  common msg header               */
-       u8         status;              /*  port enable status              */
-       u8         rsvd[3];
-       u32        msgtag;              /*  msgtag for reply                */
+       u8                 status;      /*  port enable status              */
+       u8                 rsvd[3];
+       u32        msgtag;      /*  msgtag for reply                */
 };
 
 /**
- * BFI_PPORT_H2I_ENABLE_REQ
+ * BFI_FCPORT_H2I_ENABLE_REQ
  */
-struct bfi_pport_enable_req_s {
+struct bfi_fcport_enable_req_s {
        struct bfi_mhdr_s  mh;          /*  msg header                      */
-       u32        rsvd1;
-       wwn_t           nwwn;           /*  node wwn of physical port       */
-       wwn_t           pwwn;           /*  port wwn of physical port       */
-       struct bfa_pport_cfg_s port_cfg;        /*  port configuration      */
-       union bfi_addr_u  stats_dma_addr;       /*  DMA address for stats  */
-       u32        msgtag;              /*  msgtag for reply                */
-       u32        rsvd2;
+       u32        rsvd1;
+       wwn_t              nwwn;        /*  node wwn of physical port       */
+       wwn_t              pwwn;        /*  port wwn of physical port       */
+       struct bfa_pport_cfg_s port_cfg; /*  port configuration     */
+       union bfi_addr_u   stats_dma_addr; /*  DMA address for stats        */
+       u32        msgtag;      /*  msgtag for reply                */
+       u32        rsvd2;
 };
 
 /**
- * BFI_PPORT_I2H_ENABLE_RSP
+ * BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ
  */
-#define bfi_pport_enable_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_DISABLE_REQ
- */
-#define bfi_pport_disable_req_t struct bfi_pport_generic_req_s
-
-/**
- * BFI_PPORT_I2H_DISABLE_RSP
- */
-#define bfi_pport_disable_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_GET_STATS_REQ
- */
-#define bfi_pport_get_stats_req_t struct bfi_pport_generic_req_s
-
-/**
- * BFI_PPORT_I2H_GET_STATS_RSP
- */
-#define bfi_pport_get_stats_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_CLEAR_STATS_REQ
- */
-#define bfi_pport_clear_stats_req_t struct bfi_pport_generic_req_s
-
-/**
- * BFI_PPORT_I2H_CLEAR_STATS_RSP
- */
-#define bfi_pport_clear_stats_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_GET_QOS_STATS_REQ
- */
-#define bfi_pport_get_qos_stats_req_t struct bfi_pport_generic_req_s
-
-/**
- * BFI_PPORT_H2I_GET_QOS_STATS_RSP
- */
-#define bfi_pport_get_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ
- */
-#define bfi_pport_clear_qos_stats_req_t struct bfi_pport_generic_req_s
-
-/**
- * BFI_PPORT_H2I_CLEAR_QOS_STATS_RSP
- */
-#define bfi_pport_clear_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
-
-/**
- * BFI_PPORT_H2I_SET_SVC_PARAMS_REQ
- */
-struct bfi_pport_set_svc_params_req_s {
+struct bfi_fcport_set_svc_params_req_s {
        struct bfi_mhdr_s  mh;          /*  msg header */
-       u16        tx_bbcredit; /*  Tx credits */
-       u16        rsvd;
+       u16        tx_bbcredit; /*  Tx credits */
+       u16        rsvd;
 };
 
 /**
- * BFI_PPORT_I2H_SET_SVC_PARAMS_RSP
- */
-
-/**
- * BFI_PPORT_I2H_EVENT
+ * BFI_FCPORT_I2H_EVENT
  */
-struct bfi_pport_event_s {
+struct bfi_fcport_event_s {
        struct bfi_mhdr_s       mh;     /*  common msg header */
        struct bfa_pport_link_s link_state;
 };
 
-union bfi_pport_h2i_msg_u {
+/**
+ * fcport H2I message
+ */
+union bfi_fcport_h2i_msg_u {
        struct bfi_mhdr_s                       *mhdr;
-       struct bfi_pport_enable_req_s           *penable;
-       struct bfi_pport_generic_req_s          *pdisable;
-       struct bfi_pport_generic_req_s          *pgetstats;
-       struct bfi_pport_generic_req_s          *pclearstats;
-       struct bfi_pport_set_svc_params_req_s   *psetsvcparams;
-       struct bfi_pport_get_qos_stats_req_s    *pgetqosstats;
-       struct bfi_pport_generic_req_s          *pclearqosstats;
+       struct bfi_fcport_enable_req_s          *penable;
+       struct bfi_fcport_req_s                 *pdisable;
+       struct bfi_fcport_set_svc_params_req_s  *psetsvcparams;
+       struct bfi_fcport_req_s                 *pstatsget;
+       struct bfi_fcport_req_s                 *pstatsclear;
 };
 
-union bfi_pport_i2h_msg_u {
+/**
+ * fcport I2H message
+ */
+union bfi_fcport_i2h_msg_u {
        struct bfi_msg_s                        *msg;
-       struct bfi_pport_generic_rsp_s          *enable_rsp;
-       struct bfi_pport_disable_rsp_s          *disable_rsp;
-       struct bfi_pport_generic_rsp_s          *getstats_rsp;
-       struct bfi_pport_clear_stats_rsp_s      *clearstats_rsp;
-       struct bfi_pport_set_svc_params_rsp_s   *setsvcparasm_rsp;
-       struct bfi_pport_get_qos_stats_rsp_s    *getqosstats_rsp;
-       struct bfi_pport_clear_qos_stats_rsp_s  *clearqosstats_rsp;
-       struct bfi_pport_event_s                *event;
+       struct bfi_fcport_rsp_s                 *penable_rsp;
+       struct bfi_fcport_rsp_s                 *pdisable_rsp;
+       struct bfi_fcport_rsp_s                 *psetsvcparams_rsp;
+       struct bfi_fcport_rsp_s                 *pstatsget_rsp;
+       struct bfi_fcport_rsp_s                 *pstatsclear_rsp;
+       struct bfi_fcport_event_s               *event;
 };
 
 #pragma pack()
 
 #endif /* __BFI_PPORT_H__ */
-
index 43ba706..a75a1f3 100644 (file)
 enum {
        BFA_TRC_CNA_CEE         = 1,
        BFA_TRC_CNA_PORT        = 2,
+       BFA_TRC_CNA_IOC     = 3,
+       BFA_TRC_CNA_DIAG    = 4,
+       BFA_TRC_CNA_IOC_CB  = 5,
+       BFA_TRC_CNA_IOC_CT  = 6,
 };
 
 #endif /* __BFA_CNA_TRCMOD_H__ */
index 761cbe2..bc334e0 100644 (file)
@@ -157,7 +157,7 @@ typedef void (*bfa_log_cb_t)(struct bfa_log_mod_s *log_mod, u32 msg_id,
 
 
 struct bfa_log_mod_s {
-       char            instance_info[16];      /*  instance info */
+       char            instance_info[BFA_STRING_32];   /*  instance info */
        int             log_level[BFA_LOG_MODULE_ID_MAX + 1];
                                                /*  log level for modules */
        bfa_log_cb_t    cbfn;                   /*  callback function */
index 670f86e..f5bef63 100644 (file)
@@ -80,7 +80,8 @@ enum bfa_plog_mid {
        BFA_PL_MID_HAL_FCXP     = 4,
        BFA_PL_MID_HAL_UF       = 5,
        BFA_PL_MID_FCS          = 6,
-       BFA_PL_MID_MAX          = 7
+       BFA_PL_MID_LPS          = 7,
+       BFA_PL_MID_MAX          = 8
 };
 
 #define BFA_PL_MID_STRLEN    8
@@ -118,7 +119,11 @@ enum bfa_plog_eid {
        BFA_PL_EID_RSCN                 = 17,
        BFA_PL_EID_DEBUG                = 18,
        BFA_PL_EID_MISC                 = 19,
-       BFA_PL_EID_MAX                  = 20
+       BFA_PL_EID_FIP_FCF_DISC         = 20,
+       BFA_PL_EID_FIP_FCF_CVL          = 21,
+       BFA_PL_EID_LOGIN                = 22,
+       BFA_PL_EID_LOGO                 = 23,
+       BFA_PL_EID_MAX                  = 24
 };
 
 #define BFA_PL_ENAME_STRLEN            8
index b0a92ba..11fba90 100644 (file)
 #define __BFA_SM_H__
 
 typedef void (*bfa_sm_t)(void *sm, int event);
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc_s
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_sm_state_decl(oc, st, otype, etype)         \
+       static void oc ## _sm_ ## st(otype * fsm, etype event)
 
 #define bfa_sm_set_state(_sm, _state)  ((_sm)->sm = (bfa_sm_t)(_state))
 #define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
index 4c81a61..3524469 100644 (file)
 #include <defs/bfa_defs_audit.h>
 #include <defs/bfa_defs_ethport.h>
 
+#define BFA_AEN_MAX_APP         5
+
+enum bfa_aen_app {
+       bfa_aen_app_bcu = 0,    /* No thread for bcu */
+       bfa_aen_app_hcm = 1,
+       bfa_aen_app_cim = 2,
+       bfa_aen_app_snia = 3,
+       bfa_aen_app_test = 4,   /* To be removed after unit test */
+};
+
 enum bfa_aen_category {
        BFA_AEN_CAT_ADAPTER     = 1,
        BFA_AEN_CAT_PORT        = 2,
index dd19c83..45df328 100644 (file)
@@ -23,6 +23,7 @@
 #define PRIVATE_KEY                    19009
 #define KEY_LEN                                32399
 #define BFA_AUTH_SECRET_STRING_LEN     256
+#define BFA_AUTH_FAIL_NO_PASSWORD      0xFE
 #define BFA_AUTH_FAIL_TIMEOUT          0xFF
 
 /**
@@ -41,6 +42,27 @@ enum bfa_auth_status {
        BFA_AUTH_STATUS_UNKNOWN = 9,    /*  authentication status unknown */
 };
 
+enum bfa_auth_rej_code {
+       BFA_AUTH_RJT_CODE_AUTH_FAILURE   = 1, /* auth failure */
+       BFA_AUTH_RJT_CODE_LOGICAL_ERR    = 2, /* logical error */
+};
+
+/**
+ * Authentication reject codes
+ */
+enum bfa_auth_rej_code_exp {
+       BFA_AUTH_MECH_NOT_USABLE        = 1, /* auth. mechanism not usable */
+       BFA_AUTH_DH_GROUP_NOT_USABLE    = 2, /* DH Group not usable */
+       BFA_AUTH_HASH_FUNC_NOT_USABLE   = 3, /* hash Function not usable */
+       BFA_AUTH_AUTH_XACT_STARTED      = 4, /* auth xact started */
+       BFA_AUTH_AUTH_FAILED            = 5, /* auth failed */
+       BFA_AUTH_INCORRECT_PLD          = 6, /* incorrect payload */
+       BFA_AUTH_INCORRECT_PROTO_MSG    = 7, /* incorrect proto msg */
+       BFA_AUTH_RESTART_AUTH_PROTO     = 8, /* restart auth protocol */
+       BFA_AUTH_AUTH_CONCAT_NOT_SUPP   = 9, /* auth concat not supported */
+       BFA_AUTH_PROTO_VER_NOT_SUPP     = 10,/* proto version not supported */
+};
+
 struct auth_proto_stats_s {
        u32        auth_rjts;
        u32        auth_negs;
index 520a22f..b0ac9ac 100644 (file)
 
 #define BFA_CEE_LLDP_MAX_STRING_LEN (128)
 
-
-/* FIXME: this is coming from the protocol spec. Can the host & apps share the
-   protocol .h files ?
- */
 #define BFA_CEE_LLDP_SYS_CAP_OTHER       0x0001
 #define BFA_CEE_LLDP_SYS_CAP_REPEATER    0x0002
 #define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE  0x0004
@@ -94,9 +90,10 @@ struct bfa_cee_dcbx_cfg_s {
 /* CEE status */
 /* Making this to tri-state for the benefit of port list command */
 enum bfa_cee_status_e {
-    CEE_PHY_DOWN = 0,
-    CEE_PHY_UP = 1,
-    CEE_UP = 2,
+       CEE_UP = 0,
+       CEE_PHY_UP = 1,
+       CEE_LOOPBACK = 2,
+       CEE_PHY_DOWN = 3,
 };
 
 /* CEE Query */
@@ -107,7 +104,8 @@ struct bfa_cee_attr_s {
        struct bfa_cee_dcbx_cfg_s dcbx_remote;
        mac_t src_mac;
        u8 link_speed;
-       u8 filler[3];
+       u8 nw_priority;
+       u8 filler[2];
 };
 
 
index 5704980..50382dd 100644 (file)
@@ -21,6 +21,7 @@
 /**
  * Driver statistics
  */
+struct bfa_driver_stats_s {
        u16    tm_io_abort;
     u16    tm_io_abort_comp;
     u16    tm_lun_reset;
@@ -34,7 +35,7 @@
     u64    output_req;
     u64    input_words;
     u64    output_words;
-} bfa_driver_stats_t;
+};
 
 
 #endif /* __BFA_DEFS_DRIVER_H__ */
index 79f9b3e..b4fa092 100644 (file)
@@ -19,6 +19,7 @@
 #define __BFA_DEFS_ETHPORT_H__
 
 #include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_port.h>
 #include <protocol/types.h>
 #include <cna/pstats/phyport_defs.h>
 #include <cna/pstats/ethport_defs.h>
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
new file mode 100644 (file)
index 0000000..a07ef4a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *  bfa_defs_fcport.h
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) 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.
+ */
+#ifndef __BFA_DEFS_FCPORT_H__
+#define __BFA_DEFS_FCPORT_H__
+
+#include <defs/bfa_defs_types.h>
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+/**
+ * FCoE statistics
+ */
+struct bfa_fcoe_stats_s {
+       u64     secs_reset;     /*  Seconds since stats reset        */
+       u64     cee_linkups;    /*  CEE link up              */
+       u64     cee_linkdns;    /*  CEE link down                    */
+       u64     fip_linkups;    /*  FIP link up              */
+       u64     fip_linkdns;    /*  FIP link down                    */
+       u64     fip_fails;      /*  FIP failures                     */
+       u64     mac_invalids;   /*  Invalid mac assignments          */
+       u64     vlan_req;       /*  Vlan requests                    */
+       u64     vlan_notify;    /*  Vlan notifications               */
+       u64     vlan_err;       /*  Vlan notification errors         */
+       u64     vlan_timeouts;  /*  Vlan request timeouts            */
+       u64     vlan_invalids;  /*  Vlan invalids                    */
+       u64     disc_req;       /*  Discovery requests               */
+       u64     disc_rsp;       /*  Discovery responses      */
+       u64     disc_err;       /*  Discovery error frames           */
+       u64     disc_unsol;     /*  Discovery unsolicited            */
+       u64     disc_timeouts;  /*  Discovery timeouts               */
+       u64     disc_fcf_unavail; /*  Discovery FCF not avail        */
+       u64     linksvc_unsupp; /*  FIP link service req unsupp.    */
+       u64     linksvc_err;    /*  FIP link service req errors     */
+       u64     logo_req;       /*  FIP logo                         */
+       u64     clrvlink_req;   /*  Clear virtual link requests     */
+       u64     op_unsupp;      /*  FIP operation unsupp.            */
+       u64     untagged;       /*  FIP untagged frames      */
+       u64     txf_ucast;      /*  Tx FCoE unicast frames           */
+       u64     txf_ucast_vlan; /*  Tx FCoE unicast vlan frames     */
+       u64     txf_ucast_octets; /*  Tx FCoE unicast octets         */
+       u64     txf_mcast;      /*  Tx FCoE mutlicast frames         */
+       u64     txf_mcast_vlan; /*  Tx FCoE mutlicast vlan frames   */
+       u64     txf_mcast_octets; /*  Tx FCoE multicast octets       */
+       u64     txf_bcast;      /*  Tx FCoE broadcast frames         */
+       u64     txf_bcast_vlan; /*  Tx FCoE broadcast vlan frames   */
+       u64     txf_bcast_octets; /*  Tx FCoE broadcast octets       */
+       u64     txf_timeout;    /*  Tx timeouts              */
+       u64     txf_parity_errors; /*  Transmit parity err           */
+       u64     txf_fid_parity_errors; /*  Transmit FID parity err  */
+       u64     tx_pause;       /*  Tx pause frames                  */
+       u64     tx_zero_pause;  /*  Tx zero pause frames             */
+       u64     tx_first_pause; /*  Tx first pause frames            */
+       u64     rx_pause;       /*  Rx pause frames                  */
+       u64     rx_zero_pause;  /*  Rx zero pause frames             */
+       u64     rx_first_pause; /*  Rx first pause frames            */
+       u64     rxf_ucast_octets; /*  Rx unicast octets      */
+       u64     rxf_ucast;      /*  Rx unicast frames                */
+       u64     rxf_ucast_vlan; /*  Rx unicast vlan frames           */
+       u64     rxf_mcast_octets; /*  Rx multicast octets            */
+       u64     rxf_mcast;      /*  Rx multicast frames      */
+       u64     rxf_mcast_vlan; /*  Rx multicast vlan frames         */
+       u64     rxf_bcast_octets; /*  Rx broadcast octests           */
+       u64     rxf_bcast;      /*  Rx broadcast frames      */
+       u64     rxf_bcast_vlan; /*  Rx broadcast vlan frames         */
+};
+
+/**
+ * QoS or FCoE stats (fcport stats excluding physical FC port stats)
+ */
+union bfa_fcport_stats_u {
+       struct bfa_qos_stats_s  fcqos;
+       struct bfa_fcoe_stats_s fcoe;
+};
+
+#pragma pack()
+
+#endif  /* __BFA_DEFS_FCPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h
deleted file mode 100644 (file)
index 9ccf53b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) 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.
- */
-
-#ifndef __BFA_DEFS_IM_COMMON_H__
-#define __BFA_DEFS_IM_COMMON_H__
-
-#define        BFA_ADAPTER_NAME_LEN    256
-#define BFA_ADAPTER_GUID_LEN    256
-#define RESERVED_VLAN_NAME      L"PORT VLAN"
-#define PASSTHRU_VLAN_NAME      L"PASSTHRU VLAN"
-
-       u64     tx_pkt_cnt;
-       u64     rx_pkt_cnt;
-       u32     duration;
-       u8              status;
-} bfa_im_stats_t, *pbfa_im_stats_t;
-
-#endif /* __BFA_DEFS_IM_COMMON_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h
deleted file mode 100644 (file)
index a486a7e..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) 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.
- */
-
-#ifndef __BFA_DEFS_IM_TEAM_H__
-#define __BFA_DEFS_IM_TEAM_H__
-
-#include <protocol/types.h>
-
-#define        BFA_TEAM_MAX_PORTS      8
-#define        BFA_TEAM_NAME_LEN       256
-#define BFA_MAX_NUM_TEAMS      16
-#define BFA_TEAM_INVALID_DELAY -1
-
-       BFA_LACP_RATE_SLOW = 1,
-       BFA_LACP_RATE_FAST
-} bfa_im_lacp_rate_t;
-
-       BFA_TEAM_MODE_FAIL_OVER = 1,
-       BFA_TEAM_MODE_FAIL_BACK,
-       BFA_TEAM_MODE_LACP,
-       BFA_TEAM_MODE_NONE
-} bfa_im_team_mode_t;
-
-       BFA_XMIT_POLICY_L2 = 1,
-       BFA_XMIT_POLICY_L3_L4
-} bfa_im_xmit_policy_t;
-
-       bfa_im_team_mode_t     team_mode;
-       bfa_im_lacp_rate_t     lacp_rate;
-       bfa_im_xmit_policy_t   xmit_policy;
-       int               delay;
-       wchar_t           primary[BFA_ADAPTER_NAME_LEN];
-       wchar_t           preferred_primary[BFA_ADAPTER_NAME_LEN];
-       mac_t             mac;
-       u16               num_ports;
-       u16          num_vlans;
-       u16 vlan_list[BFA_MAX_VLANS_PER_PORT];
-       wchar_t  team_guid_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_GUID_LEN];
-       wchar_t  ioc_name_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_NAME_LEN];
-} bfa_im_team_attr_t;
-
-       wchar_t                      team_name[BFA_TEAM_NAME_LEN];
-       bfa_im_xmit_policy_t     xmit_policy;
-       int                      delay;
-       wchar_t                  primary[BFA_ADAPTER_NAME_LEN];
-       wchar_t                  preferred_primary[BFA_ADAPTER_NAME_LEN];
-} bfa_im_team_edit_t, *pbfa_im_team_edit_t;
-
-       wchar_t                                 team_name[BFA_TEAM_NAME_LEN];
-       bfa_im_team_mode_t      team_mode;
-       mac_t                   mac;
-} bfa_im_team_info_t;
-
-       bfa_im_team_info_t              team_info[BFA_MAX_NUM_TEAMS];
-       u16                             num_teams;
-} bfa_im_team_list_t, *pbfa_im_team_list_t;
-
-#endif /* __BFA_DEFS_IM_TEAM_H__ */
index b1d532d..8d8e6a9 100644 (file)
@@ -126,6 +126,7 @@ struct bfa_ioc_attr_s {
        struct bfa_ioc_driver_attr_s    driver_attr;    /*  driver attr    */
        struct bfa_ioc_pci_attr_s       pci_attr;
        u8                              port_id;        /*  port number    */
+       u8                              rsvd[7];        /*!< 64bit align    */
 };
 
 /**
@@ -143,8 +144,8 @@ enum bfa_ioc_aen_event {
  * BFA IOC level event data, now just a place holder
  */
 struct bfa_ioc_aen_data_s {
-       enum bfa_ioc_type_e ioc_type;
        wwn_t   pwwn;
+       s16 ioc_type;
        mac_t   mac;
 };
 
index d76bcbd..c290fb1 100644 (file)
@@ -26,6 +26,8 @@
 
 #define BFA_IOCFC_INTR_DELAY   1125
 #define BFA_IOCFC_INTR_LATENCY 225
+#define BFA_IOCFCOE_INTR_DELAY  25
+#define BFA_IOCFCOE_INTR_LATENCY 5
 
 /**
  * Interrupt coalescing configuration.
@@ -50,7 +52,7 @@ struct bfa_iocfc_fwcfg_s {
        u16        num_fcxp_reqs;       /*  unassisted FC exchanges     */
        u16        num_uf_bufs; /*  unsolicited recv buffers    */
        u8              num_cqs;
-       u8              rsvd;
+       u8              rsvd[5];
 };
 
 struct bfa_iocfc_drvcfg_s {
@@ -224,18 +226,24 @@ struct bfa_fw_port_physm_stats_s {
 
 
 struct bfa_fw_fip_stats_s {
+    u32    vlan_req;           /*  vlan discovery requests             */
+    u32    vlan_notify;        /*  vlan notifications                  */
+    u32    vlan_err;           /*  vlan response error                 */
+    u32    vlan_timeouts;      /*  vlan disvoery timeouts              */
+    u32    vlan_invalids;      /*  invalid vlan in discovery advert.   */
     u32    disc_req;           /*  Discovery solicit requests          */
     u32    disc_rsp;           /*  Discovery solicit response          */
     u32    disc_err;           /*  Discovery advt. parse errors        */
     u32    disc_unsol;         /*  Discovery unsolicited               */
     u32    disc_timeouts;      /*  Discovery timeouts                  */
+    u32    disc_fcf_unavail;   /*  Discovery FCF Not Avail.            */
     u32    linksvc_unsupp;     /*  Unsupported link service req        */
     u32    linksvc_err;        /*  Parse error in link service req     */
     u32    logo_req;           /*  Number of FIP logos received        */
     u32    clrvlink_req;       /*  Clear virtual link req              */
     u32    op_unsupp;          /*  Unsupported FIP operation           */
     u32    untagged;           /*  Untagged frames (ignored)           */
-    u32    rsvd;
+    u32           invalid_version;    /*!< Invalid FIP version           */
 };
 
 
index 7359f82..0952a13 100644 (file)
@@ -59,8 +59,8 @@ enum bfa_lport_aen_event {
  */
 struct bfa_lport_aen_data_s {
        u16        vf_id;       /*  vf_id of this logical port */
-       u16        rsvd;
-       enum bfa_port_role roles;       /*  Logical port mode,IM/TM/IP etc */
+       s16         roles;  /*  Logical port mode,IM/TM/IP etc */
+       u32        rsvd;
        wwn_t           ppwwn;  /*  WWN of its physical port */
        wwn_t           lpwwn;  /*  WWN of this logical port */
 };
index 13fd4ab..c5bd9c3 100644 (file)
 /**
  * Manufacturing block version
  */
-#define BFA_MFG_VERSION                                1
+#define BFA_MFG_VERSION                                2
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER                                2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN                       128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN                                4
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE                    16
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER                                2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN                       128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN                                4
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE                    16
 
 /**
  * Manufacturing block format
 #define BFA_MFG_SERIALNUM_SIZE                 11
 #define BFA_MFG_PARTNUM_SIZE                   14
 #define BFA_MFG_SUPPLIER_ID_SIZE               10
-#define BFA_MFG_SUPPLIER_PARTNUM_SIZE  20
-#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE        20
-#define BFA_MFG_SUPPLIER_REVISION_SIZE 4
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE          20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE                20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE         4
 #define STRSZ(_n)      (((_n) + 4) & ~3)
 
 /**
+ * Manufacturing card type
+ */
+enum {
+       BFA_MFG_TYPE_CB_MAX  = 825,      /*  Crossbow card type max     */
+       BFA_MFG_TYPE_FC8P2   = 825,      /*  8G 2port FC card           */
+       BFA_MFG_TYPE_FC8P1   = 815,      /*  8G 1port FC card           */
+       BFA_MFG_TYPE_FC4P2   = 425,      /*  4G 2port FC card           */
+       BFA_MFG_TYPE_FC4P1   = 415,      /*  4G 1port FC card           */
+       BFA_MFG_TYPE_CNA10P2 = 1020,     /*  10G 2port CNA card */
+       BFA_MFG_TYPE_CNA10P1 = 1010,     /*  10G 1port CNA card */
+};
+
+#pragma pack(1)
+
+/**
+ * Card type to port number conversion
+ */
+#define bfa_mfg_type2port_num(card_type) (((card_type) / 10) % 10)
+
+
+/**
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_block_s {
+};
+
+/**
  * VPD data length
  */
-#define BFA_MFG_VPD_LEN     256
+#define BFA_MFG_VPD_LEN                512
+
+#define BFA_MFG_VPD_PCI_HDR_OFF                137
+#define BFA_MFG_VPD_PCI_VER_MASK       0x07    /*  version mask 3 bits */
+#define BFA_MFG_VPD_PCI_VDR_MASK       0xf8    /*  vendor mask 5 bits */
+
+/**
+ * VPD vendor tag
+ */
+enum {
+       BFA_MFG_VPD_UNKNOWN     = 0,     /*  vendor unknown             */
+       BFA_MFG_VPD_IBM         = 1,     /*  vendor IBM                 */
+       BFA_MFG_VPD_HP          = 2,     /*  vendor HP                  */
+       BFA_MFG_VPD_DELL        = 3,     /*  vendor DELL                */
+       BFA_MFG_VPD_PCI_IBM     = 0x08,  /*  PCI VPD IBM                */
+       BFA_MFG_VPD_PCI_HP      = 0x10,  /*  PCI VPD HP                 */
+       BFA_MFG_VPD_PCI_DELL    = 0x20,  /*  PCI VPD DELL               */
+       BFA_MFG_VPD_PCI_BRCD    = 0xf8,  /*  PCI VPD Brocade            */
+};
 
 /**
  * All numerical fields are in big-endian format.
  */
 struct bfa_mfg_vpd_s {
-    u8     version;    /*  vpd data version */
-    u8     vpd_sig[3]; /*  characters 'V', 'P', 'D' */
-    u8     chksum;     /*  u8 checksum */
-    u8     vendor;     /*  vendor */
-    u8     len;        /*  vpd data length excluding header */
-    u8     rsv;
-    u8     data[BFA_MFG_VPD_LEN];  /*  vpd data */
+       u8              version;        /*  vpd data version */
+       u8              vpd_sig[3];     /*  characters 'V', 'P', 'D' */
+       u8              chksum;         /*  u8 checksum */
+       u8              vendor;         /*  vendor */
+       u8      len;            /*  vpd data length excluding header */
+       u8      rsv;
+       u8              data[BFA_MFG_VPD_LEN];  /*  vpd data */
 };
 
-#pragma pack(1)
+#pragma pack()
 
 #endif /* __BFA_DEFS_MFG_H__ */
index de0696c..501bc97 100644 (file)
@@ -185,6 +185,8 @@ struct bfa_port_attr_s {
        wwn_t           fabric_name; /*  attached switch's nwwn */
        u8              fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /*  attached
                                                        * fabric's ip addr */
+       struct mac_s    fpma_mac;       /*  Lport's FPMA Mac address */
+       u16     authfail;               /*  auth failed state */
 };
 
 /**
@@ -232,14 +234,15 @@ enum bfa_port_aen_sfp_pom {
 };
 
 struct bfa_port_aen_data_s {
-       enum bfa_ioc_type_e ioc_type;
-       wwn_t           pwwn;         /*  WWN of the physical port */
-       wwn_t           fwwn;         /*  WWN of the fabric port */
-       mac_t           mac;          /*  MAC addres of the ethernet port,
-                                      * applicable to CNA port only */
-       int             phy_port_num; /*! For SFP related events */
-       enum bfa_port_aen_sfp_pom level; /*  Only transitions will
-                                         * be informed */
+       wwn_t           pwwn;         /*  WWN of the physical port */
+       wwn_t           fwwn;         /*  WWN of the fabric port */
+       s32         phy_port_num; /*! For SFP related events */
+       s16         ioc_type;
+       s16         level;        /*  Only transitions will
+                                       * be informed */
+       struct mac_s    mac;          /*  MAC address of the ethernet port,
+                                       * applicable to CNA port only */
+       s16         rsvd;
 };
 
 #endif /* __BFA_DEFS_PORT_H__ */
index bf32041..26e5cc7 100644 (file)
@@ -232,7 +232,7 @@ struct bfa_pport_attr_s {
        u32             pid;            /*  port ID */
        enum bfa_pport_type     port_type;      /*  current topology */
        u32             loopback;       /*  external loopback */
-       u32             rsvd1;
+       u32             authfail;       /* auth fail state */
        u32             rsvd2;          /*  padding for 64 bit */
 };
 
@@ -240,73 +240,79 @@ struct bfa_pport_attr_s {
  *             FC Port statistics.
  */
 struct bfa_pport_fc_stats_s {
-       u64        secs_reset;  /*  seconds since stats is reset */
-       u64        tx_frames;   /*  transmitted frames */
-       u64        tx_words;    /*  transmitted words */
-       u64        rx_frames;   /*  received frames */
-       u64        rx_words;    /*  received words */
-       u64        lip_count;   /*  LIPs seen */
-       u64        nos_count;   /*  NOS count */
-       u64        error_frames;        /*  errored frames (sent?) */
-       u64        dropped_frames;      /*  dropped frames */
-       u64        link_failures;       /*  link failure count */
-       u64        loss_of_syncs;       /*  loss of sync count */
-       u64        loss_of_signals;/*  loss of signal count */
-       u64        primseq_errs;        /*  primitive sequence protocol */
-       u64        bad_os_count;        /*  invalid ordered set */
-       u64        err_enc_out; /*  Encoding error outside frame */
-       u64        invalid_crcs;        /*  frames received with invalid CRC*/
-       u64     undersized_frm; /*  undersized frames */
-       u64     oversized_frm;  /*  oversized frames */
-       u64     bad_eof_frm;    /*  frames with bad EOF */
-       struct bfa_qos_stats_s  qos_stats;      /*  QoS statistics */
+       u64    secs_reset; /* Seconds since stats is reset     */
+       u64    tx_frames;  /* Tx frames                */
+       u64    tx_words;   /* Tx words                 */
+       u64    tx_lip;     /* TX LIP               */
+       u64    tx_nos;     /* Tx NOS               */
+       u64    tx_ols;     /* Tx OLS               */
+       u64    tx_lr;      /* Tx LR                */
+       u64    tx_lrr;     /* Tx LRR               */
+       u64    rx_frames;  /* Rx frames                */
+       u64    rx_words;   /* Rx words                 */
+       u64    lip_count;  /* Rx LIP                   */
+       u64    nos_count;  /* Rx NOS               */
+       u64    ols_count;  /* Rx OLS               */
+       u64    lr_count;   /* Rx LR                */
+       u64    lrr_count;  /* Rx LRR               */
+       u64    invalid_crcs;   /* Rx CRC err frames            */
+       u64    invalid_crc_gd_eof; /* Rx CRC err good EOF frames   */
+       u64    undersized_frm; /* Rx undersized frames         */
+       u64    oversized_frm;  /* Rx oversized frames          */
+       u64    bad_eof_frm;    /* Rx frames with bad EOF       */
+       u64    error_frames;   /* Errored frames           */
+       u64    dropped_frames; /* Dropped frames           */
+       u64    link_failures;  /* Link Failure (LF) count          */
+       u64    loss_of_syncs;  /* Loss of sync count           */
+       u64    loss_of_signals;/* Loss of signal count         */
+       u64    primseq_errs;   /* Primitive sequence protocol err. */
+       u64    bad_os_count;   /* Invalid ordered sets         */
+       u64    err_enc_out;    /* Encoding err nonframe_8b10b      */
+       u64    err_enc;    /* Encoding err frame_8b10b         */
 };
 
 /**
  *             Eth Port statistics.
  */
 struct bfa_pport_eth_stats_s {
-       u64     secs_reset;     /*  seconds since stats is reset */
-       u64     frame_64;      /*  both rx and tx counter */
-       u64     frame_65_127;      /* both rx and tx counter */
-       u64     frame_128_255;     /* both rx and tx counter */
-       u64     frame_256_511;     /* both rx and tx counter */
-       u64     frame_512_1023;    /* both rx and tx counter */
-       u64     frame_1024_1518;   /* both rx and tx counter */
-       u64     frame_1519_1522;   /* both rx and tx counter */
-
-       u64     tx_bytes;
-       u64     tx_packets;
-       u64     tx_mcast_packets;
-       u64     tx_bcast_packets;
-       u64     tx_control_frame;
-       u64     tx_drop;
-       u64     tx_jabber;
-       u64     tx_fcs_error;
-       u64     tx_fragments;
-
-       u64     rx_bytes;
-       u64     rx_packets;
-       u64     rx_mcast_packets;
-       u64     rx_bcast_packets;
-       u64     rx_control_frames;
-       u64     rx_unknown_opcode;
-       u64     rx_drop;
-       u64     rx_jabber;
-       u64     rx_fcs_error;
-       u64     rx_alignment_error;
-       u64     rx_frame_length_error;
-       u64     rx_code_error;
-       u64     rx_fragments;
-
-       u64     rx_pause; /* BPC */
-       u64     rx_zero_pause; /*  BPC Pause cancellation */
-       u64     tx_pause;      /* BPC */
-       u64     tx_zero_pause; /*  BPC Pause cancellation */
-       u64     rx_fcoe_pause; /* BPC */
-       u64     rx_fcoe_zero_pause; /*  BPC Pause cancellation */
-       u64     tx_fcoe_pause;      /* BPC */
-       u64     tx_fcoe_zero_pause; /*  BPC Pause cancellation */
+       u64    secs_reset;   /* Seconds since stats is reset   */
+       u64    frame_64;     /* Frames 64 bytes            */
+       u64    frame_65_127;     /* Frames 65-127 bytes        */
+       u64    frame_128_255;    /* Frames 128-255 bytes       */
+       u64    frame_256_511;    /* Frames 256-511 bytes       */
+       u64    frame_512_1023;   /* Frames 512-1023 bytes          */
+       u64    frame_1024_1518;  /* Frames 1024-1518 bytes         */
+       u64    frame_1519_1522;  /* Frames 1519-1522 bytes         */
+       u64    tx_bytes;     /* Tx bytes               */
+       u64    tx_packets;   /* Tx packets             */
+       u64    tx_mcast_packets; /* Tx multicast packets       */
+       u64    tx_bcast_packets; /* Tx broadcast packets       */
+       u64    tx_control_frame; /* Tx control frame           */
+       u64    tx_drop;      /* Tx drops               */
+       u64    tx_jabber;    /* Tx jabber              */
+       u64    tx_fcs_error;     /* Tx FCS error           */
+       u64    tx_fragments;     /* Tx fragments           */
+       u64    rx_bytes;     /* Rx bytes               */
+       u64    rx_packets;   /* Rx packets             */
+       u64    rx_mcast_packets; /* Rx multicast packets       */
+       u64    rx_bcast_packets; /* Rx broadcast packets       */
+       u64    rx_control_frames; /* Rx control frames         */
+       u64    rx_unknown_opcode; /* Rx unknown opcode         */
+       u64    rx_drop;      /* Rx drops               */
+       u64    rx_jabber;    /* Rx jabber              */
+       u64    rx_fcs_error;     /* Rx FCS errors              */
+       u64    rx_alignment_error; /* Rx alignment errors          */
+       u64    rx_frame_length_error; /* Rx frame len errors       */
+       u64    rx_code_error;    /* Rx code errors             */
+       u64    rx_fragments;     /* Rx fragments           */
+       u64    rx_pause;     /* Rx pause               */
+       u64    rx_zero_pause;    /* Rx zero pause              */
+       u64    tx_pause;     /* Tx pause               */
+       u64    tx_zero_pause;    /* Tx zero pause              */
+       u64    rx_fcoe_pause;    /* Rx fcoe pause              */
+       u64    rx_fcoe_zero_pause; /* Rx FCoE zero pause       */
+       u64    tx_fcoe_pause;    /* Tx FCoE pause              */
+       u64    tx_fcoe_zero_pause; /* Tx FCoE zero pause       */
 };
 
 /**
@@ -333,8 +339,7 @@ struct bfa_pport_fcpmap_s {
 };
 
 /**
- *              Port RNID info.
- */
+ *              Port RNI        */
 struct bfa_pport_rnid_s {
        wwn_t             wwn;
        u32          unittype;
@@ -347,6 +352,23 @@ struct bfa_pport_rnid_s {
        u16          topologydiscoveryflags;
 };
 
+struct bfa_fcport_fcf_s {
+       wwn_t           name;           /* FCF name                 */
+       wwn_t           fabric_name;    /* Fabric Name              */
+       u8              fipenabled;     /* FIP enabled or not       */
+       u8              fipfailed;      /* FIP failed or not        */
+       u8              resv[2];
+       u8              pri;            /* FCF priority             */
+       u8              version;        /* FIP version used         */
+       u8              available;      /* Available  for  login    */
+       u8              fka_disabled;   /* FKA is disabled          */
+       u8              maxsz_verified; /* FCoE max size verified   */
+       u8              fc_map[3];      /* FC map                   */
+       u16             vlan;           /* FCoE vlan tag/priority   */
+       u32             fka_adv_per;    /* FIP  ka advert. period   */
+       struct mac_s    mac;            /* FCF mac                  */
+};
+
 /**
  *             Link state information
  */
@@ -378,6 +400,7 @@ struct bfa_pport_link_s {
                        struct fc_alpabm_s     alpabm;     /*  alpa bitmap */
                } loop_info;
        } tl;
+       struct bfa_fcport_fcf_s fcf;    /*!< FCF information (for FCoE) */
 };
 
 #endif /* __BFA_DEFS_PPORT_H__ */
index cdceaeb..4374494 100644 (file)
@@ -180,8 +180,8 @@ enum bfa_status {
        BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /*  Given adapter is part
                                                    * of another team */
        BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /*  Adapter has VLANs configured.
-                                             * Delete all VLANs before
-                                             * creating team */
+                                             * Delete all VLANs to become
+                                             * part of the team */
        BFA_STATUS_IM_PVID_MISMATCH = 116, /*  Mismatching PVIDs configured
                                            * for adapters */
        BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /*  Mismatching link speeds
@@ -213,7 +213,7 @@ enum bfa_status {
                                             * loaded */
        BFA_STATUS_CARD_TYPE_MISMATCH = 131, /*  Card type mismatch */
        BFA_STATUS_BAD_ASICBLK = 132, /*  Bad ASIC block */
-       BFA_STATUS_NO_DRIVER = 133, /*  Storage/Ethernet driver not loaded */
+       BFA_STATUS_NO_DRIVER = 133, /*  Brocade adapter/driver not installed or loaded */
        BFA_STATUS_INVALID_MAC = 134, /*  Invalid mac address */
        BFA_STATUS_IM_NO_VLAN = 135, /*  No VLANs configured on the adapter */
        BFA_STATUS_IM_ETH_LB_FAILED = 136, /*  Ethernet loopback test failed */
@@ -228,8 +228,7 @@ enum bfa_status {
        BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /*  Acquiring Network Subsytem
                                                 * handle Failed. Please try
                                                 * after some time */
-       BFA_STATUS_IM_NOT_BOUND = 143, /*  Brocade 10G Ethernet Service is not
-                                       * Enabled on this port */
+       BFA_STATUS_IM_NOT_BOUND = 143, /*  IM driver is not active */
        BFA_STATUS_INSUFFICIENT_PERMS = 144, /*  User doesn't have sufficient
                                              * permissions to execute the BCU
                                              * application */
@@ -242,6 +241,14 @@ enum bfa_status {
                                          * failed */
        BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
                                            * failed */
+       BFA_STATUS_IM_PORT_IN_TEAM = 150, /*  Port is already part of the
+                                          * team */
+       BFA_STATUS_IM_VLAN_NOT_FOUND = 151, /*  VLAN ID doesn't exists */
+       BFA_STATUS_IM_TEAM_NOT_FOUND = 152, /*  Teaming configuration doesn't
+                                            * exists */
+       BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153, /*  Given settings are not
+                                               * allowed for the current
+                                               * Teaming mode */
        BFA_STATUS_MAX_VAL              /*  Unknown error code */
 };
 #define bfa_status_t enum bfa_status
index a6c70ae..52585d3 100644 (file)
@@ -70,7 +70,6 @@ void            bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv);
  */
 void            bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv);
 
-void            bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim_drv);
 void            bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim_drv);
 
 #endif /* __BFAD_FCB_FCPIM_H__ */
index 627669c..f2fd35f 100644 (file)
@@ -49,6 +49,7 @@ struct bfa_fcs_s {
        struct bfa_trc_mod_s  *trcmod;  /*  tracing module */
        struct bfa_aen_s      *aen;     /*  aen component */
        bfa_boolean_t   vf_enabled;     /*  VF mode is enabled */
+       bfa_boolean_t   fdmi_enabled;   /*!< FDMI is enabled */
        bfa_boolean_t min_cfg;          /* min cfg enabled/disabled */
        u16        port_vfid;   /*  port default VF ID */
        struct bfa_fcs_driver_info_s driver_info;
@@ -60,10 +61,12 @@ struct bfa_fcs_s {
 /*
  * bfa fcs API functions
  */
-void bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
                        bfa_boolean_t min_cfg);
+void bfa_fcs_init(struct bfa_fcs_s *fcs);
 void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
                        struct bfa_fcs_driver_info_s *driver_info);
+void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable);
 void bfa_fcs_exit(struct bfa_fcs_s *fcs);
 void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
 void bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod);
index 967ceb0..ceaefd3 100644 (file)
@@ -34,14 +34,6 @@ struct bfa_fcs_s;
 struct bfa_fcs_fabric_s;
 
 /*
-* @todo : need to move to a global config file.
- * Maximum Vports supported per physical port or vf.
- */
-#define BFA_FCS_MAX_VPORTS_SUPP_CB  255
-#define BFA_FCS_MAX_VPORTS_SUPP_CT  191
-
-/*
-* @todo : need to move to a global config file.
  * Maximum Rports supported per port (physical/logical).
  */
 #define BFA_FCS_MAX_RPORTS_SUPP  256   /* @todo : tentative value */
index 0412aea..5f8f5e3 100644 (file)
        (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 3)
 #define BFA_LOG_HAL_SM_ASSERT \
        (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 4)
+#define BFA_LOG_HAL_DRIVER_ERROR \
+       (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 5)
+#define BFA_LOG_HAL_DRIVER_CONFIG_ERROR \
+       (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 6)
+#define BFA_LOG_HAL_MBOX_ERROR \
+       (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 7)
 #endif
index 317c054..bd451db 100644 (file)
                (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 10)
 #define BFA_LOG_LINUX_SCSI_ABORT_COMP \
                (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 11)
+#define BFA_LOG_LINUX_DRIVER_CONFIG_ERROR \
+               (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 12)
+#define BFA_LOG_LINUX_BNA_STATE_MACHINE \
+               (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 13)
+#define BFA_LOG_LINUX_IOC_ERROR \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 14)
+#define BFA_LOG_LINUX_RESOURCE_ALLOC_ERROR \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 15)
+#define BFA_LOG_LINUX_RING_BUFFER_ERROR \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 16)
+#define BFA_LOG_LINUX_DRIVER_ERROR \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 17)
+#define BFA_LOG_LINUX_DRIVER_DIAG \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 18)
+#define BFA_LOG_LINUX_DRIVER_AEN \
+       (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 19)
 #endif
index 14969ee..8d10380 100644 (file)
@@ -50,6 +50,11 @@ struct fchs_s {
 
        u32        ro;          /* relative offset */
 };
+
+#define FC_SOF_LEN      4
+#define FC_EOF_LEN      4
+#define FC_CRC_LEN      4
+
 /*
  * Fibre Channel BB_E Header Structure
  */
diff --git a/drivers/scsi/bfa/include/protocol/pcifw.h b/drivers/scsi/bfa/include/protocol/pcifw.h
deleted file mode 100644 (file)
index 6830dc3..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) 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.
- */
-
-/**
- *  pcifw.h PCI FW related headers
- */
-
-#ifndef __PCIFW_H__
-#define __PCIFW_H__
-
-#pragma pack(1)
-
-struct pnp_hdr_s{
-  u32  signature;      /* "$PnP" */
-  u8   rev;            /* Struct revision */
-  u8   len;            /* Header structure len in multiples
-                                * of 16 bytes */
-  u16  off;            /* Offset to next header 00 if none */
-  u8   rsvd;           /* Reserved byte */
-  u8   cksum;          /* 8-bit checksum for this header */
-  u32  pnp_dev_id;     /* PnP Device Id */
-  u16  mfstr;          /* Pointer to manufacturer string */
-  u16  prstr;          /* Pointer to product string */
-  u8   devtype[3];     /* Device Type Code */
-  u8   devind;         /* Device Indicator */
-  u16  bcventr;        /* Bootstrap entry vector */
-  u16  rsvd2;          /* Reserved */
-  u16  sriv;           /* Static resource information vector */
-};
-
-struct pci_3_0_ds_s{
- u32   sig;            /* Signature "PCIR" */
- u16   vendid;         /* Vendor ID */
- u16   devid;          /* Device ID */
- u16   devlistoff;     /* Device List Offset */
- u16   len;            /* PCI Data Structure Length */
- u8    rev;            /* PCI Data Structure Revision */
- u8    clcode[3];      /* Class Code */
- u16   imglen;         /* Code image length in multiples of
-                                * 512 bytes */
- u16   coderev;        /* Revision level of code/data */
- u8    codetype;       /* Code type 0x00 - BIOS */
- u8    indr;           /* Last image indicator */
- u16   mrtimglen;      /* Max Run Time Image Length */
- u16   cuoff;          /* Config Utility Code Header Offset */
- u16   dmtfclp;        /* DMTF CLP entry point offset */
-};
-
-struct pci_optrom_hdr_s{
- u16   sig;            /* Signature 0x55AA */
- u8    len;            /* Option ROM length in units of 512 bytes */
- u8    inivec[3];      /* Initialization vector */
- u8    rsvd[16];       /* Reserved field */
- u16   verptr;         /* Pointer to version string - private */
- u16   pcids;          /* Pointer to PCI data structure */
- u16   pnphdr;         /* Pointer to PnP expansion header */
-};
-
-#pragma pack()
-
-#endif
index f7c7f4f..f6342ef 100644 (file)
@@ -162,7 +162,7 @@ bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
        len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
                             bfa_fcs_port_get_fcid(port), 0,
                             port->port_cfg.pwwn, port->port_cfg.nwwn,
-                                bfa_pport_get_maxfrsize(port->fcs->bfa));
+                                bfa_fcport_get_maxfrsize(port->fcs->bfa));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                          FC_CLASS_3, len, &fchs,
index 1e06792..d3907d1 100644 (file)
@@ -156,7 +156,7 @@ bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
        /*
         * Get Physical port's current speed
         */
-       bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+       bfa_fcport_get_attr(port->fcs->bfa, &pport_attr);
        pport_speed = pport_attr.speed;
        bfa_trc(fcs, pport_speed);
 
@@ -235,7 +235,8 @@ bfa_fcs_port_get_info(struct bfa_fcs_port_s *port,
                port_info->port_wwn = bfa_fcs_port_get_pwwn(port);
                port_info->node_wwn = bfa_fcs_port_get_nwwn(port);
 
-               port_info->max_vports_supp = bfa_fcs_vport_get_max(port->fcs);
+               port_info->max_vports_supp =
+                       bfa_lps_get_max_vport(port->fcs->bfa);
                port_info->num_vports_inuse =
                        bfa_fcs_fabric_vport_count(port->fabric);
                port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP;
index c96b3ca..5e8c8de 100644 (file)
@@ -118,7 +118,7 @@ bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -141,7 +141,7 @@ bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -190,7 +190,7 @@ bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -216,7 +216,7 @@ bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -230,10 +230,6 @@ bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
        switch (event) {
        case MSSM_EVENT_PORT_OFFLINE:
                bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
-               /*
-                * now invoke MS related sub-modules
-                */
-               bfa_fcs_port_fdmi_offline(ms);
                break;
 
        case MSSM_EVENT_PORT_FABRIC_RSCN:
@@ -243,7 +239,7 @@ bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -266,7 +262,7 @@ bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -304,7 +300,7 @@ bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -330,7 +326,7 @@ bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -466,7 +462,7 @@ bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -502,7 +498,7 @@ bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -528,7 +524,7 @@ bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ms->port->fcs, event);
        }
 }
 
@@ -637,7 +633,7 @@ bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
                             bfa_os_hton3b(FC_MGMT_SERVER),
                             bfa_fcs_port_get_fcid(port), 0,
                             port->port_cfg.pwwn, port->port_cfg.nwwn,
-                            bfa_pport_get_maxfrsize(port->fcs->bfa));
+                            bfa_fcport_get_maxfrsize(port->fcs->bfa));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response,
@@ -735,6 +731,7 @@ bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port)
 
        ms->port = port;
        bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE);
+       bfa_fcs_port_fdmi_offline(ms);
 }
 
 void
index 2f8b880..d20dd7e 100644 (file)
@@ -164,7 +164,7 @@ bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -187,7 +187,7 @@ bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -221,7 +221,7 @@ bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -247,7 +247,7 @@ bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -270,7 +270,7 @@ bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -304,7 +304,7 @@ bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -330,7 +330,7 @@ bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -353,7 +353,7 @@ bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -390,7 +390,7 @@ bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -413,7 +413,7 @@ bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -436,7 +436,7 @@ bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -494,7 +494,7 @@ bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -517,7 +517,7 @@ bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 static void
@@ -539,7 +539,7 @@ bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -575,7 +575,7 @@ bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -598,7 +598,7 @@ bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -626,7 +626,7 @@ bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(ns->port->fcs, event);
        }
 }
 
@@ -660,7 +660,7 @@ bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
                             bfa_os_hton3b(FC_NAME_SERVER),
                             bfa_fcs_port_get_fcid(port), 0,
                             port->port_cfg.pwwn, port->port_cfg.nwwn,
-                            bfa_pport_get_maxfrsize(port->fcs->bfa));
+                            bfa_fcport_get_maxfrsize(port->fcs->bfa));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response,
index 9cf58bb..8e73dd9 100644 (file)
@@ -224,7 +224,7 @@ bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -276,7 +276,7 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -332,7 +332,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -406,7 +406,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -481,7 +481,7 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -534,7 +534,7 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -589,7 +589,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -646,7 +646,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -704,7 +704,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -754,7 +754,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -816,7 +816,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -846,7 +846,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -869,7 +869,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -905,7 +905,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -925,10 +925,17 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
        case RPSM_EVENT_HCB_OFFLINE:
        case RPSM_EVENT_ADDRESS_CHANGE:
                if (bfa_fcs_port_is_online(rport->port)) {
-                       bfa_sm_set_state(rport,
-                                        bfa_fcs_rport_sm_nsdisc_sending);
-                       rport->ns_retries = 0;
-                       bfa_fcs_rport_send_gidpn(rport, NULL);
+                       if (bfa_fcs_fabric_is_switched(rport->port->fabric)) {
+                               bfa_sm_set_state(rport,
+                                       bfa_fcs_rport_sm_nsdisc_sending);
+                               rport->ns_retries = 0;
+                               bfa_fcs_rport_send_gidpn(rport, NULL);
+                       } else {
+                               bfa_sm_set_state(rport,
+                                       bfa_fcs_rport_sm_plogi_sending);
+                               rport->plogi_retries = 0;
+                               bfa_fcs_rport_send_plogi(rport, NULL);
+                       }
                } else {
                        rport->pid = 0;
                        bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
@@ -951,7 +958,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1011,7 +1018,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1038,7 +1045,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1073,7 +1080,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1132,7 +1139,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1188,7 +1195,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1249,7 +1256,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1334,7 +1341,7 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -1366,7 +1373,7 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
                             bfa_fcs_port_get_fcid(port), 0,
                             port->port_cfg.pwwn, port->port_cfg.nwwn,
-                            bfa_pport_get_maxfrsize(port->fcs->bfa));
+                            bfa_fcport_get_maxfrsize(port->fcs->bfa));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                      FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response,
@@ -1478,7 +1485,7 @@ bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
                                 bfa_fcs_port_get_fcid(port), rport->reply_oxid,
                                 port->port_cfg.pwwn, port->port_cfg.nwwn,
-                                bfa_pport_get_maxfrsize(port->fcs->bfa));
+                                bfa_fcport_get_maxfrsize(port->fcs->bfa));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
@@ -1813,7 +1820,7 @@ bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport,
        /*
         * get curent speed from pport attributes from BFA
         */
-       bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+       bfa_fcport_get_attr(port->fcs->bfa, &pport_attr);
 
        speeds.port_op_speed = fc_bfa_speed_to_rpsc_operspeed(pport_attr.speed);
 
@@ -2032,13 +2039,10 @@ bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport,
 
        switch (event) {
        case BFA_RPORT_AEN_ONLINE:
-               bfa_log(logmod, BFA_AEN_RPORT_ONLINE, rpwwn_ptr, lpwwn_ptr);
-               break;
        case BFA_RPORT_AEN_OFFLINE:
-               bfa_log(logmod, BFA_AEN_RPORT_OFFLINE, rpwwn_ptr, lpwwn_ptr);
-               break;
        case BFA_RPORT_AEN_DISCONNECT:
-               bfa_log(logmod, BFA_AEN_RPORT_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
+               bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, event),
+                       rpwwn_ptr, lpwwn_ptr);
                break;
        case BFA_RPORT_AEN_QOS_PRIO:
                aen_data.rport.priv.qos = data->priv.qos;
@@ -2164,7 +2168,7 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
                bfa_trc(port->fcs, port->fabric->bb_credit);
 
                port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred);
-               bfa_pport_set_tx_bbcredit(port->fcs->bfa,
+               bfa_fcport_set_tx_bbcredit(port->fcs->bfa,
                                          port->fabric->bb_credit);
        }
 
@@ -2575,23 +2579,6 @@ bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
 }
 
 /**
- *   Module initialization
- */
-void
-bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs)
-{
-}
-
-/**
- *   Module cleanup
- */
-void
-bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs)
-{
-       bfa_fcs_modexit_comp(fcs);
-}
-
-/**
  * Return state of rport.
  */
 int
index 3dae177..a441f41 100644 (file)
@@ -102,7 +102,7 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
        rport_attr->qos_attr = qos_attr;
 
        rport_attr->trl_enforced = BFA_FALSE;
-       if (bfa_pport_is_ratelim(port->fcs->bfa)) {
+       if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
                if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) ||
                        (rport->rpf.rpsc_speed <
                        bfa_fcs_port_get_rport_max_speed(port)))
index e1932c8..ae7bba6 100644 (file)
@@ -91,7 +91,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -114,7 +114,7 @@ bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -160,7 +160,7 @@ bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -186,7 +186,7 @@ bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -206,7 +206,7 @@ bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 
@@ -229,7 +229,7 @@ bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(rport->fcs, event);
        }
 }
 /**
index bd4771f..8fe09ba 100644 (file)
@@ -90,7 +90,7 @@ bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(scn->port->fcs, event);
        }
 }
 
@@ -109,7 +109,7 @@ bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(scn->port->fcs, event);
        }
 }
 
@@ -137,7 +137,7 @@ bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(scn->port->fcs, event);
        }
 }
 
@@ -157,7 +157,7 @@ bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(scn->port->fcs, event);
        }
 }
 
@@ -171,7 +171,7 @@ bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(scn->port->fcs, event);
        }
 }
 
index e90f1e3..27cd619 100644 (file)
@@ -122,7 +122,7 @@ bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -165,7 +165,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -202,7 +202,7 @@ bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -249,7 +249,7 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -283,7 +283,7 @@ bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -310,7 +310,7 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -339,7 +339,7 @@ bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -387,7 +387,7 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -419,7 +419,7 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
                break;
 
        default:
-               bfa_assert(0);
+               bfa_sm_fault(__vport_fcs(vport), event);
        }
 }
 
@@ -447,22 +447,8 @@ bfa_fcs_vport_aen_post(bfa_fcs_lport_t *port, enum bfa_lport_aen_event event)
 
        bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
 
-       switch (event) {
-       case BFA_LPORT_AEN_NPIV_DUP_WWN:
-               bfa_log(logmod, BFA_AEN_LPORT_NPIV_DUP_WWN, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_NPIV_FABRIC_MAX:
-               bfa_log(logmod, BFA_AEN_LPORT_NPIV_FABRIC_MAX, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       case BFA_LPORT_AEN_NPIV_UNKNOWN:
-               bfa_log(logmod, BFA_AEN_LPORT_NPIV_UNKNOWN, lpwwn_ptr,
-                       role_str[role / 2]);
-               break;
-       default:
-               break;
-       }
+       bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr,
+                       role_str[role/2]);
 
        aen_data.lport.vf_id = port->fabric->vf_id;
        aen_data.lport.roles = role;
@@ -478,7 +464,7 @@ static void
 bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport)
 {
        bfa_lps_fdisc(vport->lps, vport,
-                     bfa_pport_get_maxfrsize(__vport_bfa(vport)),
+                     bfa_fcport_get_maxfrsize(__vport_bfa(vport)),
                      __vport_pwwn(vport), __vport_nwwn(vport));
        vport->vport_stats.fdisc_sent++;
 }
@@ -617,38 +603,6 @@ bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport)
 }
 
 /**
- *   Module initialization
- */
-void
-bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs)
-{
-}
-
-/**
- *   Module cleanup
- */
-void
-bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs)
-{
-       bfa_fcs_modexit_comp(fcs);
-}
-
-u32
-bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs)
-{
-       struct bfa_ioc_attr_s ioc_attr;
-
-       bfa_get_attr(fcs->bfa, &ioc_attr);
-
-       if (ioc_attr.pci_attr.device_id == BFA_PCI_DEVICE_ID_CT)
-               return BFA_FCS_MAX_VPORTS_SUPP_CT;
-       else
-               return BFA_FCS_MAX_VPORTS_SUPP_CB;
-}
-
-
-
-/**
  *  fcs_vport_api Virtual port API
  */
 
@@ -684,7 +638,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
                return BFA_STATUS_VPORT_EXISTS;
 
        if (bfa_fcs_fabric_vport_count(&fcs->fabric) ==
-           bfa_fcs_vport_get_max(fcs))
+               bfa_lps_get_max_vport(fcs->bfa))
                return BFA_STATUS_VPORT_MAX;
 
        vport->lps = bfa_lps_alloc(fcs->bfa);
@@ -694,7 +648,8 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
        vport->vport_drv = vport_drv;
        bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
 
-       bfa_fcs_lport_init(&vport->lport, fcs, vf_id, vport_cfg, vport);
+       bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport);
+       bfa_fcs_lport_init(&vport->lport, vport_cfg);
 
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE);
 
@@ -888,4 +843,15 @@ bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg)
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
 }
 
+/**
+ * Received clear virtual link
+ */
+void
+bfa_cb_lps_cvl_event(void *bfad, void *uarg)
+{
+       struct bfa_fcs_vport_s *vport = uarg;
 
+       /* Send an Offline followed by an ONLINE */
+       bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
+       bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
+}
index 1c4d121..cb71dc9 100644 (file)
@@ -1989,7 +1989,7 @@ static struct scsi_host_template bnx2i_host_template = {
        .queuecommand           = iscsi_queuecommand,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
-       .eh_target_reset_handler = iscsi_eh_target_reset,
+       .eh_target_reset_handler = iscsi_eh_recover_target,
        .change_queue_depth     = iscsi_change_queue_depth,
        .can_queue              = 1024,
        .max_sectors            = 127,
index 412853c..b7c3058 100644 (file)
@@ -915,7 +915,7 @@ static struct scsi_host_template cxgb3i_host_template = {
        .cmd_per_lun            = ISCSI_DEF_CMD_PER_LUN,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
-       .eh_target_reset_handler = iscsi_eh_target_reset,
+       .eh_target_reset_handler = iscsi_eh_recover_target,
        .target_alloc           = iscsi_target_alloc,
        .use_clustering         = DISABLE_CLUSTERING,
        .this_id                = -1,
index 6196675..63032ec 100644 (file)
@@ -272,7 +272,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
        int len = 0;
 
        rq = blk_get_request(sdev->request_queue,
-                       (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
+                       (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
        if (!rq) {
                sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
                return NULL;
@@ -286,14 +286,17 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
                len = sizeof(short_trespass);
                rq->cmd_flags |= REQ_RW;
                rq->cmd[1] = 0x10;
+               rq->cmd[4] = len;
                break;
        case MODE_SELECT_10:
                len = sizeof(long_trespass);
                rq->cmd_flags |= REQ_RW;
                rq->cmd[1] = 0x10;
+               rq->cmd[8] = len;
                break;
        case INQUIRY:
                len = CLARIION_BUFFER_SIZE;
+               rq->cmd[4] = len;
                memset(buffer, 0, len);
                break;
        default:
@@ -301,7 +304,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
                break;
        }
 
-       rq->cmd[4] = len;
        rq->cmd_type = REQ_TYPE_BLOCK_PC;
        rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                         REQ_FAILFAST_DRIVER;
index 03697ba..183d3a4 100644 (file)
@@ -43,6 +43,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 #include <linux/cciss_ioctl.h>
 #include <linux/string.h>
 #include <linux/bitmap.h>
@@ -52,7 +53,7 @@
 #include "hpsa.h"
 
 /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "2.0.1-3"
+#define HPSA_DRIVER_VERSION "2.0.2-1"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -134,6 +135,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
 static void hpsa_scan_start(struct Scsi_Host *);
 static int hpsa_scan_finished(struct Scsi_Host *sh,
        unsigned long elapsed_time);
+static int hpsa_change_queue_depth(struct scsi_device *sdev,
+       int qdepth, int reason);
 
 static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
 static int hpsa_slave_alloc(struct scsi_device *sdev);
@@ -182,8 +185,8 @@ static struct scsi_host_template hpsa_driver_template = {
        .queuecommand           = hpsa_scsi_queue_command,
        .scan_start             = hpsa_scan_start,
        .scan_finished          = hpsa_scan_finished,
+       .change_queue_depth     = hpsa_change_queue_depth,
        .this_id                = -1,
-       .sg_tablesize           = MAXSGENTRIES,
        .use_clustering         = ENABLE_CLUSTERING,
        .eh_device_reset_handler = hpsa_eh_device_reset_handler,
        .ioctl                  = hpsa_ioctl,
@@ -208,133 +211,6 @@ static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
        return (struct ctlr_info *) *priv;
 }
 
-static struct task_struct *hpsa_scan_thread;
-static DEFINE_MUTEX(hpsa_scan_mutex);
-static LIST_HEAD(hpsa_scan_q);
-static int hpsa_scan_func(void *data);
-
-/**
- * add_to_scan_list() - add controller to rescan queue
- * @h:               Pointer to the controller.
- *
- * Adds the controller to the rescan queue if not already on the queue.
- *
- * returns 1 if added to the queue, 0 if skipped (could be on the
- * queue already, or the controller could be initializing or shutting
- * down).
- **/
-static int add_to_scan_list(struct ctlr_info *h)
-{
-       struct ctlr_info *test_h;
-       int found = 0;
-       int ret = 0;
-
-       if (h->busy_initializing)
-               return 0;
-
-       /*
-        * If we don't get the lock, it means the driver is unloading
-        * and there's no point in scheduling a new scan.
-        */
-       if (!mutex_trylock(&h->busy_shutting_down))
-               return 0;
-
-       mutex_lock(&hpsa_scan_mutex);
-       list_for_each_entry(test_h, &hpsa_scan_q, scan_list) {
-               if (test_h == h) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found && !h->busy_scanning) {
-               INIT_COMPLETION(h->scan_wait);
-               list_add_tail(&h->scan_list, &hpsa_scan_q);
-               ret = 1;
-       }
-       mutex_unlock(&hpsa_scan_mutex);
-       mutex_unlock(&h->busy_shutting_down);
-
-       return ret;
-}
-
-/**
- * remove_from_scan_list() - remove controller from rescan queue
- * @h:                    Pointer to the controller.
- *
- * Removes the controller from the rescan queue if present. Blocks if
- * the controller is currently conducting a rescan.  The controller
- * can be in one of three states:
- * 1. Doesn't need a scan
- * 2. On the scan list, but not scanning yet (we remove it)
- * 3. Busy scanning (and not on the list). In this case we want to wait for
- *    the scan to complete to make sure the scanning thread for this
- *    controller is completely idle.
- **/
-static void remove_from_scan_list(struct ctlr_info *h)
-{
-       struct ctlr_info *test_h, *tmp_h;
-
-       mutex_lock(&hpsa_scan_mutex);
-       list_for_each_entry_safe(test_h, tmp_h, &hpsa_scan_q, scan_list) {
-               if (test_h == h) { /* state 2. */
-                       list_del(&h->scan_list);
-                       complete_all(&h->scan_wait);
-                       mutex_unlock(&hpsa_scan_mutex);
-                       return;
-               }
-       }
-       if (h->busy_scanning) { /* state 3. */
-               mutex_unlock(&hpsa_scan_mutex);
-               wait_for_completion(&h->scan_wait);
-       } else { /* state 1, nothing to do. */
-               mutex_unlock(&hpsa_scan_mutex);
-       }
-}
-
-/* hpsa_scan_func() - kernel thread used to rescan controllers
- * @data:       Ignored.
- *
- * A kernel thread used scan for drive topology changes on
- * controllers. The thread processes only one controller at a time
- * using a queue.  Controllers are added to the queue using
- * add_to_scan_list() and removed from the queue either after done
- * processing or using remove_from_scan_list().
- *
- * returns 0.
- **/
-static int hpsa_scan_func(__attribute__((unused)) void *data)
-{
-       struct ctlr_info *h;
-       int host_no;
-
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-               if (kthread_should_stop())
-                       break;
-
-               while (1) {
-                       mutex_lock(&hpsa_scan_mutex);
-                       if (list_empty(&hpsa_scan_q)) {
-                               mutex_unlock(&hpsa_scan_mutex);
-                               break;
-                       }
-                       h = list_entry(hpsa_scan_q.next, struct ctlr_info,
-                                       scan_list);
-                       list_del(&h->scan_list);
-                       h->busy_scanning = 1;
-                       mutex_unlock(&hpsa_scan_mutex);
-                       host_no = h->scsi_host ?  h->scsi_host->host_no : -1;
-                       hpsa_scan_start(h->scsi_host);
-                       complete_all(&h->scan_wait);
-                       mutex_lock(&hpsa_scan_mutex);
-                       h->busy_scanning = 0;
-                       mutex_unlock(&hpsa_scan_mutex);
-               }
-       }
-       return 0;
-}
-
 static int check_for_unit_attention(struct ctlr_info *h,
        struct CommandList *c)
 {
@@ -352,21 +228,8 @@ static int check_for_unit_attention(struct ctlr_info *h,
                break;
        case REPORT_LUNS_CHANGED:
                dev_warn(&h->pdev->dev, "hpsa%d: report LUN data "
-                       "changed\n", h->ctlr);
+                       "changed, action required\n", h->ctlr);
        /*
-        * Here, we could call add_to_scan_list and wake up the scan thread,
-        * except that it's quite likely that we will get more than one
-        * REPORT_LUNS_CHANGED condition in quick succession, which means
-        * that those which occur after the first one will likely happen
-        * *during* the hpsa_scan_thread's rescan.  And the rescan code is not
-        * robust enough to restart in the middle, undoing what it has already
-        * done, and it's not clear that it's even possible to do this, since
-        * part of what it does is notify the SCSI mid layer, which starts
-        * doing it's own i/o to read partition tables and so on, and the
-        * driver doesn't have visibility to know what might need undoing.
-        * In any event, if possible, it is horribly complicated to get right
-        * so we just don't do it for now.
-        *
         * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
         */
                break;
@@ -393,10 +256,7 @@ static ssize_t host_store_rescan(struct device *dev,
        struct ctlr_info *h;
        struct Scsi_Host *shost = class_to_shost(dev);
        h = shost_to_hba(shost);
-       if (add_to_scan_list(h)) {
-               wake_up_process(hpsa_scan_thread);
-               wait_for_completion_interruptible(&h->scan_wait);
-       }
+       hpsa_scan_start(h->scsi_host);
        return count;
 }
 
@@ -983,6 +843,76 @@ static void hpsa_scsi_setup(struct ctlr_info *h)
        spin_lock_init(&h->devlock);
 }
 
+static void hpsa_free_sg_chain_blocks(struct ctlr_info *h)
+{
+       int i;
+
+       if (!h->cmd_sg_list)
+               return;
+       for (i = 0; i < h->nr_cmds; i++) {
+               kfree(h->cmd_sg_list[i]);
+               h->cmd_sg_list[i] = NULL;
+       }
+       kfree(h->cmd_sg_list);
+       h->cmd_sg_list = NULL;
+}
+
+static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h)
+{
+       int i;
+
+       if (h->chainsize <= 0)
+               return 0;
+
+       h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds,
+                               GFP_KERNEL);
+       if (!h->cmd_sg_list)
+               return -ENOMEM;
+       for (i = 0; i < h->nr_cmds; i++) {
+               h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) *
+                                               h->chainsize, GFP_KERNEL);
+               if (!h->cmd_sg_list[i])
+                       goto clean;
+       }
+       return 0;
+
+clean:
+       hpsa_free_sg_chain_blocks(h);
+       return -ENOMEM;
+}
+
+static void hpsa_map_sg_chain_block(struct ctlr_info *h,
+       struct CommandList *c)
+{
+       struct SGDescriptor *chain_sg, *chain_block;
+       u64 temp64;
+
+       chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
+       chain_block = h->cmd_sg_list[c->cmdindex];
+       chain_sg->Ext = HPSA_SG_CHAIN;
+       chain_sg->Len = sizeof(*chain_sg) *
+               (c->Header.SGTotal - h->max_cmd_sg_entries);
+       temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len,
+                               PCI_DMA_TODEVICE);
+       chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL);
+       chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL);
+}
+
+static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
+       struct CommandList *c)
+{
+       struct SGDescriptor *chain_sg;
+       union u64bit temp64;
+
+       if (c->Header.SGTotal <= h->max_cmd_sg_entries)
+               return;
+
+       chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
+       temp64.val32.lower = chain_sg->Addr.lower;
+       temp64.val32.upper = chain_sg->Addr.upper;
+       pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
 static void complete_scsi_command(struct CommandList *cp,
        int timeout, u32 tag)
 {
@@ -999,10 +929,12 @@ static void complete_scsi_command(struct CommandList *cp,
        h = cp->h;
 
        scsi_dma_unmap(cmd); /* undo the DMA mappings */
+       if (cp->Header.SGTotal > h->max_cmd_sg_entries)
+               hpsa_unmap_sg_chain_block(h, cp);
 
        cmd->result = (DID_OK << 16);           /* host byte */
        cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
-       cmd->result |= (ei->ScsiStatus << 1);
+       cmd->result |= ei->ScsiStatus;
 
        /* copy the sense data whether we need to or not. */
        memcpy(cmd->sense_buffer, ei->SenseInfo,
@@ -1203,6 +1135,7 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
        sh->max_id = HPSA_MAX_LUN;
        sh->can_queue = h->nr_cmds;
        sh->cmd_per_lun = h->nr_cmds;
+       sh->sg_tablesize = h->maxsgentries;
        h->scsi_host = sh;
        sh->hostdata[0] = (unsigned long) h;
        sh->irq = h->intr[PERF_MODE_INT];
@@ -1382,7 +1315,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
 
        if (c == NULL) {                        /* trouble... */
                dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
-               return -1;
+               return -ENOMEM;
        }
 
        fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG);
@@ -1904,16 +1837,17 @@ out:
  * dma mapping  and fills in the scatter gather entries of the
  * hpsa command, cp.
  */
-static int hpsa_scatter_gather(struct pci_dev *pdev,
+static int hpsa_scatter_gather(struct ctlr_info *h,
                struct CommandList *cp,
                struct scsi_cmnd *cmd)
 {
        unsigned int len;
        struct scatterlist *sg;
        u64 addr64;
-       int use_sg, i;
+       int use_sg, i, sg_index, chained;
+       struct SGDescriptor *curr_sg;
 
-       BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
+       BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
 
        use_sg = scsi_dma_map(cmd);
        if (use_sg < 0)
@@ -1922,15 +1856,33 @@ static int hpsa_scatter_gather(struct pci_dev *pdev,
        if (!use_sg)
                goto sglist_finished;
 
+       curr_sg = cp->SG;
+       chained = 0;
+       sg_index = 0;
        scsi_for_each_sg(cmd, sg, use_sg, i) {
+               if (i == h->max_cmd_sg_entries - 1 &&
+                       use_sg > h->max_cmd_sg_entries) {
+                       chained = 1;
+                       curr_sg = h->cmd_sg_list[cp->cmdindex];
+                       sg_index = 0;
+               }
                addr64 = (u64) sg_dma_address(sg);
                len  = sg_dma_len(sg);
-               cp->SG[i].Addr.lower =
-                       (u32) (addr64 & (u64) 0x00000000FFFFFFFF);
-               cp->SG[i].Addr.upper =
-                       (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
-               cp->SG[i].Len = len;
-               cp->SG[i].Ext = 0;  /* we are not chaining */
+               curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
+               curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+               curr_sg->Len = len;
+               curr_sg->Ext = 0;  /* we are not chaining */
+               curr_sg++;
+       }
+
+       if (use_sg + chained > h->maxSG)
+               h->maxSG = use_sg + chained;
+
+       if (chained) {
+               cp->Header.SGList = h->max_cmd_sg_entries;
+               cp->Header.SGTotal = (u16) (use_sg + 1);
+               hpsa_map_sg_chain_block(h, cp);
+               return 0;
        }
 
 sglist_finished:
@@ -2026,7 +1978,7 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
                break;
        }
 
-       if (hpsa_scatter_gather(h->pdev, c, cmd) < 0) { /* Fill SG list */
+       if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */
                cmd_free(h, c);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
@@ -2077,6 +2029,23 @@ static int hpsa_scan_finished(struct Scsi_Host *sh,
        return finished;
 }
 
+static int hpsa_change_queue_depth(struct scsi_device *sdev,
+       int qdepth, int reason)
+{
+       struct ctlr_info *h = sdev_to_hba(sdev);
+
+       if (reason != SCSI_QDEPTH_DEFAULT)
+               return -ENOTSUPP;
+
+       if (qdepth < 1)
+               qdepth = 1;
+       else
+               if (qdepth > h->nr_cmds)
+                       qdepth = h->nr_cmds;
+       scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+       return sdev->queue_depth;
+}
+
 static void hpsa_unregister_scsi(struct ctlr_info *h)
 {
        /* we are being forcibly unloaded, and may not refuse. */
@@ -2961,7 +2930,7 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Send a message CDB to the firmwart. */
+/* Send a message CDB to the firmware. */
 static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
                                                unsigned char type)
 {
@@ -3296,7 +3265,7 @@ default_int_mode:
        h->intr[PERF_MODE_INT] = pdev->irq;
 }
 
-static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
 {
        ushort subsystem_vendor_id, subsystem_device_id, command;
        u32 board_id, scratchpad = 0;
@@ -3405,6 +3374,23 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
 
        h->board_id = board_id;
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+       h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+
+       /*
+        * Limit in-command s/g elements to 32 save dma'able memory.
+        * Howvever spec says if 0, use 31
+        */
+
+       h->max_cmd_sg_entries = 31;
+       if (h->maxsgentries > 512) {
+               h->max_cmd_sg_entries = 32;
+               h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1;
+               h->maxsgentries--; /* save one for chain pointer */
+       } else {
+               h->maxsgentries = 31; /* default to traditional values */
+               h->chainsize = 0;
+       }
+
        h->product_name = products[prod_index].product_name;
        h->access = *(products[prod_index].access);
        /* Allow room for some ioctls */
@@ -3532,8 +3518,6 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        h->busy_initializing = 1;
        INIT_HLIST_HEAD(&h->cmpQ);
        INIT_HLIST_HEAD(&h->reqQ);
-       mutex_init(&h->busy_shutting_down);
-       init_completion(&h->scan_wait);
        rc = hpsa_pci_init(h, pdev);
        if (rc != 0)
                goto clean1;
@@ -3587,6 +3571,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
                rc = -ENOMEM;
                goto clean4;
        }
+       if (hpsa_allocate_sg_chain_blocks(h))
+               goto clean4;
        spin_lock_init(&h->lock);
        spin_lock_init(&h->scan_lock);
        init_waitqueue_head(&h->scan_wait_queue);
@@ -3609,6 +3595,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        return 1;
 
 clean4:
+       hpsa_free_sg_chain_blocks(h);
        kfree(h->cmd_pool_bits);
        if (h->cmd_pool)
                pci_free_consistent(h->pdev,
@@ -3681,11 +3668,10 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
                return;
        }
        h = pci_get_drvdata(pdev);
-       mutex_lock(&h->busy_shutting_down);
-       remove_from_scan_list(h);
        hpsa_unregister_scsi(h);        /* unhook from SCSI subsystem */
        hpsa_shutdown(pdev);
        iounmap(h->vaddr);
+       hpsa_free_sg_chain_blocks(h);
        pci_free_consistent(h->pdev,
                h->nr_cmds * sizeof(struct CommandList),
                h->cmd_pool, h->cmd_pool_dhandle);
@@ -3703,7 +3689,6 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
         */
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
-       mutex_unlock(&h->busy_shutting_down);
        kfree(h);
 }
 
@@ -3857,23 +3842,12 @@ clean_up:
  */
 static int __init hpsa_init(void)
 {
-       int err;
-       /* Start the scan thread */
-       hpsa_scan_thread = kthread_run(hpsa_scan_func, NULL, "hpsa_scan");
-       if (IS_ERR(hpsa_scan_thread)) {
-               err = PTR_ERR(hpsa_scan_thread);
-               return -ENODEV;
-       }
-       err = pci_register_driver(&hpsa_pci_driver);
-       if (err)
-               kthread_stop(hpsa_scan_thread);
-       return err;
+       return pci_register_driver(&hpsa_pci_driver);
 }
 
 static void __exit hpsa_cleanup(void)
 {
        pci_unregister_driver(&hpsa_pci_driver);
-       kthread_stop(hpsa_scan_thread);
 }
 
 module_init(hpsa_init);
index a0502b3..1bb5233 100644 (file)
@@ -83,6 +83,10 @@ struct ctlr_info {
        unsigned int maxQsinceinit;
        unsigned int maxSG;
        spinlock_t lock;
+       int maxsgentries;
+       u8 max_cmd_sg_entries;
+       int chainsize;
+       struct SGDescriptor **cmd_sg_list;
 
        /* pointers to command and error info pool */
        struct CommandList      *cmd_pool;
@@ -97,9 +101,6 @@ struct ctlr_info {
        int                     scan_finished;
        spinlock_t              scan_lock;
        wait_queue_head_t       scan_wait_queue;
-       struct mutex            busy_shutting_down;
-       struct list_head        scan_list;
-       struct completion       scan_wait;
 
        struct Scsi_Host *scsi_host;
        spinlock_t devlock; /* to protect hba[ctlr]->dev[];  */
index 3e0abdf..56fb982 100644 (file)
@@ -23,7 +23,8 @@
 
 /* general boundary defintions */
 #define SENSEINFOBYTES          32 /* may vary between hbas */
-#define MAXSGENTRIES            31
+#define MAXSGENTRIES            32
+#define HPSA_SG_CHAIN          0x80000000
 #define MAXREPLYQS              256
 
 /* Command Status value */
@@ -305,20 +306,23 @@ struct CommandList {
        int                        cmd_type;
        long                       cmdindex;
        struct hlist_node list;
-       struct CommandList *prev;
-       struct CommandList *next;
        struct request *rq;
        struct completion *waiting;
-       int      retry_count;
        void   *scsi_cmd;
 
 /* on 64 bit architectures, to get this to be 32-byte-aligned
- * it so happens we need no padding, on 32 bit systems,
- * we need 8 bytes of padding.   This does that.
+ * it so happens we need PAD_64 bytes of padding, on 32 bit systems,
+ * we need PAD_32 bytes of padding (see below).   This does that.
+ * If it happens that 64 bit and 32 bit systems need different
+ * padding, PAD_32 and PAD_64 can be set independently, and.
+ * the code below will do the right thing.
  */
-#define COMMANDLIST_PAD ((8 - sizeof(long))/4 * 8)
+#define IS_32_BIT ((8 - sizeof(long))/4)
+#define IS_64_BIT (!IS_32_BIT)
+#define PAD_32 (4)
+#define PAD_64 (4)
+#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
        u8 pad[COMMANDLIST_PAD];
-
 };
 
 /* Configuration Table Structure */
index 732f6d3..4e577e2 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/kthread.h>
 #include <linux/of.h>
+#include <linux/pm.h>
 #include <linux/stringify.h>
 #include <asm/firmware.h>
 #include <asm/irq.h>
@@ -4736,6 +4737,27 @@ static int ibmvfc_remove(struct vio_dev *vdev)
 }
 
 /**
+ * ibmvfc_resume - Resume from suspend
+ * @dev:       device struct
+ *
+ * We may have lost an interrupt across suspend/resume, so kick the
+ * interrupt handler
+ *
+ */
+static int ibmvfc_resume(struct device *dev)
+{
+       unsigned long flags;
+       struct ibmvfc_host *vhost = dev_get_drvdata(dev);
+       struct vio_dev *vdev = to_vio_dev(dev);
+
+       spin_lock_irqsave(vhost->host->host_lock, flags);
+       vio_disable_interrupts(vdev);
+       tasklet_schedule(&vhost->tasklet);
+       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+       return 0;
+}
+
+/**
  * ibmvfc_get_desired_dma - Calculate DMA resources needed by the driver
  * @vdev:      vio device struct
  *
@@ -4755,6 +4777,10 @@ static struct vio_device_id ibmvfc_device_table[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(vio, ibmvfc_device_table);
 
+static struct dev_pm_ops ibmvfc_pm_ops = {
+       .resume = ibmvfc_resume
+};
+
 static struct vio_driver ibmvfc_driver = {
        .id_table = ibmvfc_device_table,
        .probe = ibmvfc_probe,
@@ -4763,6 +4789,7 @@ static struct vio_driver ibmvfc_driver = {
        .driver = {
                .name = IBMVFC_NAME,
                .owner = THIS_MODULE,
+               .pm = &ibmvfc_pm_ops,
        }
 };
 
index e3a18e0..dc1bcbe 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <linux/pm.h>
 #include <asm/firmware.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
@@ -1991,6 +1992,19 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
 }
 
 /**
+ * ibmvscsi_resume: Resume from suspend
+ * @dev:       device struct
+ *
+ * We may have lost an interrupt across suspend/resume, so kick the
+ * interrupt handler
+ */
+static int ibmvscsi_resume(struct device *dev)
+{
+       struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
+       return ibmvscsi_ops->resume(hostdata);
+}
+
+/**
  * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we 
  * support.
  */
@@ -2000,6 +2014,10 @@ static struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
 
+static struct dev_pm_ops ibmvscsi_pm_ops = {
+       .resume = ibmvscsi_resume
+};
+
 static struct vio_driver ibmvscsi_driver = {
        .id_table = ibmvscsi_device_table,
        .probe = ibmvscsi_probe,
@@ -2008,6 +2026,7 @@ static struct vio_driver ibmvscsi_driver = {
        .driver = {
                .name = "ibmvscsi",
                .owner = THIS_MODULE,
+               .pm = &ibmvscsi_pm_ops,
        }
 };
 
index 7642530..9cb7c6a 100644 (file)
@@ -120,6 +120,7 @@ struct ibmvscsi_ops {
                                  struct ibmvscsi_host_data *hostdata);
        int (*send_crq)(struct ibmvscsi_host_data *hostdata,
                       u64 word1, u64 word2);
+       int (*resume) (struct ibmvscsi_host_data *hostdata);
 };
 
 extern struct ibmvscsi_ops iseriesvscsi_ops;
index 0775fde..f477645 100644 (file)
@@ -158,10 +158,16 @@ static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
                                             0);
 }
 
+static int iseriesvscsi_resume(struct ibmvscsi_host_data *hostdata)
+{
+       return 0;
+}
+
 struct ibmvscsi_ops iseriesvscsi_ops = {
        .init_crq_queue = iseriesvscsi_init_crq_queue,
        .release_crq_queue = iseriesvscsi_release_crq_queue,
        .reset_crq_queue = iseriesvscsi_reset_crq_queue,
        .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
        .send_crq = iseriesvscsi_send_crq,
+       .resume = iseriesvscsi_resume,
 };
index 462a857..63a30cb 100644 (file)
@@ -334,10 +334,23 @@ static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
        return rc;
 }
 
+/**
+ * rpavscsi_resume: - resume after suspend
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ */
+static int rpavscsi_resume(struct ibmvscsi_host_data *hostdata)
+{
+       vio_disable_interrupts(to_vio_dev(hostdata->dev));
+       tasklet_schedule(&hostdata->srp_task);
+       return 0;
+}
+
 struct ibmvscsi_ops rpavscsi_ops = {
        .init_crq_queue = rpavscsi_init_crq_queue,
        .release_crq_queue = rpavscsi_release_crq_queue,
        .reset_crq_queue = rpavscsi_reset_crq_queue,
        .reenable_crq_queue = rpavscsi_reenable_crq_queue,
        .send_crq = rpavscsi_send_crq,
+       .resume = rpavscsi_resume,
 };
index 032f0d0..c79cd98 100644 (file)
@@ -72,6 +72,8 @@
 #include <linux/moduleparam.h>
 #include <linux/libata.h>
 #include <linux/hdreg.h>
+#include <linux/reboot.h>
+#include <linux/stringify.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
@@ -91,8 +93,8 @@ static unsigned int ipr_max_speed = 1;
 static int ipr_testmode = 0;
 static unsigned int ipr_fastfail = 0;
 static unsigned int ipr_transop_timeout = 0;
-static unsigned int ipr_enable_cache = 1;
 static unsigned int ipr_debug = 0;
+static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS;
 static unsigned int ipr_dual_ioa_raid = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
@@ -104,13 +106,20 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
                {
                        .set_interrupt_mask_reg = 0x0022C,
                        .clr_interrupt_mask_reg = 0x00230,
+                       .clr_interrupt_mask_reg32 = 0x00230,
                        .sense_interrupt_mask_reg = 0x0022C,
+                       .sense_interrupt_mask_reg32 = 0x0022C,
                        .clr_interrupt_reg = 0x00228,
+                       .clr_interrupt_reg32 = 0x00228,
                        .sense_interrupt_reg = 0x00224,
+                       .sense_interrupt_reg32 = 0x00224,
                        .ioarrin_reg = 0x00404,
                        .sense_uproc_interrupt_reg = 0x00214,
+                       .sense_uproc_interrupt_reg32 = 0x00214,
                        .set_uproc_interrupt_reg = 0x00214,
-                       .clr_uproc_interrupt_reg = 0x00218
+                       .set_uproc_interrupt_reg32 = 0x00214,
+                       .clr_uproc_interrupt_reg = 0x00218,
+                       .clr_uproc_interrupt_reg32 = 0x00218
                }
        },
        { /* Snipe and Scamp */
@@ -119,25 +128,59 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
                {
                        .set_interrupt_mask_reg = 0x00288,
                        .clr_interrupt_mask_reg = 0x0028C,
+                       .clr_interrupt_mask_reg32 = 0x0028C,
                        .sense_interrupt_mask_reg = 0x00288,
+                       .sense_interrupt_mask_reg32 = 0x00288,
                        .clr_interrupt_reg = 0x00284,
+                       .clr_interrupt_reg32 = 0x00284,
                        .sense_interrupt_reg = 0x00280,
+                       .sense_interrupt_reg32 = 0x00280,
                        .ioarrin_reg = 0x00504,
                        .sense_uproc_interrupt_reg = 0x00290,
+                       .sense_uproc_interrupt_reg32 = 0x00290,
                        .set_uproc_interrupt_reg = 0x00290,
-                       .clr_uproc_interrupt_reg = 0x00294
+                       .set_uproc_interrupt_reg32 = 0x00290,
+                       .clr_uproc_interrupt_reg = 0x00294,
+                       .clr_uproc_interrupt_reg32 = 0x00294
+               }
+       },
+       { /* CRoC */
+               .mailbox = 0x00040,
+               .cache_line_size = 0x20,
+               {
+                       .set_interrupt_mask_reg = 0x00010,
+                       .clr_interrupt_mask_reg = 0x00018,
+                       .clr_interrupt_mask_reg32 = 0x0001C,
+                       .sense_interrupt_mask_reg = 0x00010,
+                       .sense_interrupt_mask_reg32 = 0x00014,
+                       .clr_interrupt_reg = 0x00008,
+                       .clr_interrupt_reg32 = 0x0000C,
+                       .sense_interrupt_reg = 0x00000,
+                       .sense_interrupt_reg32 = 0x00004,
+                       .ioarrin_reg = 0x00070,
+                       .sense_uproc_interrupt_reg = 0x00020,
+                       .sense_uproc_interrupt_reg32 = 0x00024,
+                       .set_uproc_interrupt_reg = 0x00020,
+                       .set_uproc_interrupt_reg32 = 0x00024,
+                       .clr_uproc_interrupt_reg = 0x00028,
+                       .clr_uproc_interrupt_reg32 = 0x0002C,
+                       .init_feedback_reg = 0x0005C,
+                       .dump_addr_reg = 0x00064,
+                       .dump_data_reg = 0x00068
                }
        },
 };
 
 static const struct ipr_chip_t ipr_chip[] = {
-       { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, &ipr_chip_cfg[1] },
-       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, &ipr_chip_cfg[1] }
+       { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] }
 };
 
 static int ipr_max_bus_speeds [] = {
@@ -156,12 +199,13 @@ module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
 module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
 MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
-module_param_named(enable_cache, ipr_enable_cache, int, 0);
-MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
 module_param_named(debug, ipr_debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
 module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
 MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
+module_param_named(max_devs, ipr_max_devs, int, 0);
+MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. "
+                "[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -180,6 +224,20 @@ struct ipr_error_table_t ipr_error_table[] = {
        "FFFE: Soft device bus error recovered by the IOA"},
        {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL,
        "4101: Soft device bus fabric error"},
+       {0x01100100, 0, IPR_DEFAULT_LOG_LEVEL,
+       "FFFC: Logical block guard error recovered by the device"},
+       {0x01100300, 0, IPR_DEFAULT_LOG_LEVEL,
+       "FFFC: Logical block reference tag error recovered by the device"},
+       {0x01108300, 0, IPR_DEFAULT_LOG_LEVEL,
+       "4171: Recovered scatter list tag / sequence number error"},
+       {0x01109000, 0, IPR_DEFAULT_LOG_LEVEL,
+       "FF3D: Recovered logical block CRC error on IOA to Host transfer"},
+       {0x01109200, 0, IPR_DEFAULT_LOG_LEVEL,
+       "4171: Recovered logical block sequence number error on IOA to Host transfer"},
+       {0x0110A000, 0, IPR_DEFAULT_LOG_LEVEL,
+       "FFFD: Recovered logical block reference tag error detected by the IOA"},
+       {0x0110A100, 0, IPR_DEFAULT_LOG_LEVEL,
+       "FFFD: Logical block guard error recovered by the IOA"},
        {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL,
        "FFF9: Device sector reassign successful"},
        {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL,
@@ -236,12 +294,28 @@ struct ipr_error_table_t ipr_error_table[] = {
        "3120: SCSI bus is not operational"},
        {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL,
        "4100: Hard device bus fabric error"},
+       {0x04100100, 0, IPR_DEFAULT_LOG_LEVEL,
+       "310C: Logical block guard error detected by the device"},
+       {0x04100300, 0, IPR_DEFAULT_LOG_LEVEL,
+       "310C: Logical block reference tag error detected by the device"},
+       {0x04108300, 1, IPR_DEFAULT_LOG_LEVEL,
+       "4170: Scatter list tag / sequence number error"},
+       {0x04109000, 1, IPR_DEFAULT_LOG_LEVEL,
+       "8150: Logical block CRC error on IOA to Host transfer"},
+       {0x04109200, 1, IPR_DEFAULT_LOG_LEVEL,
+       "4170: Logical block sequence number error on IOA to Host transfer"},
+       {0x0410A000, 0, IPR_DEFAULT_LOG_LEVEL,
+       "310D: Logical block reference tag error detected by the IOA"},
+       {0x0410A100, 0, IPR_DEFAULT_LOG_LEVEL,
+       "310D: Logical block guard error detected by the IOA"},
        {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL,
        "9000: IOA reserved area data check"},
        {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL,
        "9001: IOA reserved area invalid data pattern"},
        {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL,
        "9002: IOA reserved area LRC error"},
+       {0x04118300, 1, IPR_DEFAULT_LOG_LEVEL,
+       "Hardware Error, IOA metadata access error"},
        {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL,
        "102E: Out of alternate sectors for disk storage"},
        {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL,
@@ -306,6 +380,8 @@ struct ipr_error_table_t ipr_error_table[] = {
        "Illegal request, commands not allowed to this device"},
        {0x05258100, 0, 0,
        "Illegal request, command not allowed to a secondary adapter"},
+       {0x05258200, 0, 0,
+       "Illegal request, command not allowed to a non-optimized resource"},
        {0x05260000, 0, 0,
        "Illegal request, invalid field in parameter list"},
        {0x05260100, 0, 0,
@@ -468,7 +544,10 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
        trace_entry->time = jiffies;
        trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
        trace_entry->type = type;
-       trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command;
+       if (ipr_cmd->ioa_cfg->sis64)
+               trace_entry->ata_op_code = ipr_cmd->i.ata_ioadl.regs.command;
+       else
+               trace_entry->ata_op_code = ipr_cmd->ioarcb.u.add_data.u.regs.command;
        trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
        trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
        trace_entry->u.add_data = add_data;
@@ -488,16 +567,23 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
-       dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
+       dma_addr_t dma_addr = ipr_cmd->dma_addr;
 
        memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
-       ioarcb->write_data_transfer_length = 0;
+       ioarcb->data_transfer_length = 0;
        ioarcb->read_data_transfer_length = 0;
-       ioarcb->write_ioadl_len = 0;
+       ioarcb->ioadl_len = 0;
        ioarcb->read_ioadl_len = 0;
-       ioarcb->write_ioadl_addr =
-               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
-       ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+
+       if (ipr_cmd->ioa_cfg->sis64)
+               ioarcb->u.sis64_addr_data.data_ioadl_addr =
+                       cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
+       else {
+               ioarcb->write_ioadl_addr =
+                       cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
+               ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+       }
+
        ioasa->ioasc = 0;
        ioasa->residual_data_len = 0;
        ioasa->u.gata.status = 0;
@@ -562,10 +648,15 @@ static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,
        ioa_cfg->allow_interrupts = 0;
 
        /* Set interrupt mask to stop all new interrupts */
-       writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);
+       if (ioa_cfg->sis64)
+               writeq(~0, ioa_cfg->regs.set_interrupt_mask_reg);
+       else
+               writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);
 
        /* Clear any pending interrupts */
-       writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg);
+       if (ioa_cfg->sis64)
+               writel(~0, ioa_cfg->regs.clr_interrupt_reg);
+       writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg32);
        int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
 }
 
@@ -693,6 +784,35 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
 }
 
 /**
+ * ipr_send_command -  Send driver initiated requests.
+ * @ipr_cmd:           ipr command struct
+ *
+ * This function sends a command to the adapter using the correct write call.
+ * In the case of sis64, calculate the ioarcb size required. Then or in the
+ * appropriate bits.
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_send_command(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       dma_addr_t send_dma_addr = ipr_cmd->dma_addr;
+
+       if (ioa_cfg->sis64) {
+               /* The default size is 256 bytes */
+               send_dma_addr |= 0x1;
+
+               /* If the number of ioadls * size of ioadl > 128 bytes,
+                  then use a 512 byte ioarcb */
+               if (ipr_cmd->dma_use_sg * sizeof(struct ipr_ioadl64_desc) > 128 )
+                       send_dma_addr |= 0x4;
+               writeq(send_dma_addr, ioa_cfg->regs.ioarrin_reg);
+       } else
+               writel(send_dma_addr, ioa_cfg->regs.ioarrin_reg);
+}
+
+/**
  * ipr_do_req -  Send driver initiated requests.
  * @ipr_cmd:           ipr command struct
  * @done:                      done function
@@ -724,8 +844,8 @@ static void ipr_do_req(struct ipr_cmnd *ipr_cmd,
        ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0);
 
        mb();
-       writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
-              ioa_cfg->regs.ioarrin_reg);
+
+       ipr_send_command(ipr_cmd);
 }
 
 /**
@@ -747,6 +867,51 @@ static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd)
 }
 
 /**
+ * ipr_init_ioadl - initialize the ioadl for the correct SIS type
+ * @ipr_cmd:   ipr command struct
+ * @dma_addr:  dma address
+ * @len:       transfer length
+ * @flags:     ioadl flag value
+ *
+ * This function initializes an ioadl in the case where there is only a single
+ * descriptor.
+ *
+ * Return value:
+ *     nothing
+ **/
+static void ipr_init_ioadl(struct ipr_cmnd *ipr_cmd, dma_addr_t dma_addr,
+                          u32 len, int flags)
+{
+       struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
+       struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
+
+       ipr_cmd->dma_use_sg = 1;
+
+       if (ipr_cmd->ioa_cfg->sis64) {
+               ioadl64->flags = cpu_to_be32(flags);
+               ioadl64->data_len = cpu_to_be32(len);
+               ioadl64->address = cpu_to_be64(dma_addr);
+
+               ipr_cmd->ioarcb.ioadl_len =
+                       cpu_to_be32(sizeof(struct ipr_ioadl64_desc));
+               ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len);
+       } else {
+               ioadl->flags_and_data_len = cpu_to_be32(flags | len);
+               ioadl->address = cpu_to_be32(dma_addr);
+
+               if (flags == IPR_IOADL_FLAGS_READ_LAST) {
+                       ipr_cmd->ioarcb.read_ioadl_len =
+                               cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+                       ipr_cmd->ioarcb.read_data_transfer_length = cpu_to_be32(len);
+               } else {
+                       ipr_cmd->ioarcb.ioadl_len =
+                               cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+                       ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len);
+               }
+       }
+}
+
+/**
  * ipr_send_blocking_cmd - Send command and sleep on its completion.
  * @ipr_cmd:   ipr command struct
  * @timeout_func:      function to invoke if command times out
@@ -803,11 +968,8 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,
                ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff;
                ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff;
 
-               ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam));
-               ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-               ipr_cmd->ioadl[0].flags_and_data_len =
-                       cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam));
-               ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma);
+               ipr_init_ioadl(ipr_cmd, hostrcb->hostrcb_dma,
+                              sizeof(hostrcb->hcam), IPR_IOADL_FLAGS_READ_LAST);
 
                if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE)
                        ipr_cmd->done = ipr_process_ccn;
@@ -817,22 +979,54 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,
                ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR);
 
                mb();
-               writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
-                      ioa_cfg->regs.ioarrin_reg);
+
+               ipr_send_command(ipr_cmd);
        } else {
                list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
        }
 }
 
 /**
+ * ipr_update_ata_class - Update the ata class in the resource entry
+ * @res:       resource entry struct
+ * @proto:     cfgte device bus protocol value
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto)
+{
+       switch(proto) {
+       case IPR_PROTO_SATA:
+       case IPR_PROTO_SAS_STP:
+               res->ata_class = ATA_DEV_ATA;
+               break;
+       case IPR_PROTO_SATA_ATAPI:
+       case IPR_PROTO_SAS_STP_ATAPI:
+               res->ata_class = ATA_DEV_ATAPI;
+               break;
+       default:
+               res->ata_class = ATA_DEV_UNKNOWN;
+               break;
+       };
+}
+
+/**
  * ipr_init_res_entry - Initialize a resource entry struct.
  * @res:       resource entry struct
+ * @cfgtew:    config table entry wrapper struct
  *
  * Return value:
  *     none
  **/
-static void ipr_init_res_entry(struct ipr_resource_entry *res)
+static void ipr_init_res_entry(struct ipr_resource_entry *res,
+                              struct ipr_config_table_entry_wrapper *cfgtew)
 {
+       int found = 0;
+       unsigned int proto;
+       struct ipr_ioa_cfg *ioa_cfg = res->ioa_cfg;
+       struct ipr_resource_entry *gscsi_res = NULL;
+
        res->needs_sync_complete = 0;
        res->in_erp = 0;
        res->add_to_ml = 0;
@@ -840,6 +1034,205 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res)
        res->resetting_device = 0;
        res->sdev = NULL;
        res->sata_port = NULL;
+
+       if (ioa_cfg->sis64) {
+               proto = cfgtew->u.cfgte64->proto;
+               res->res_flags = cfgtew->u.cfgte64->res_flags;
+               res->qmodel = IPR_QUEUEING_MODEL64(res);
+               res->type = cfgtew->u.cfgte64->res_type & 0x0f;
+
+               memcpy(res->res_path, &cfgtew->u.cfgte64->res_path,
+                       sizeof(res->res_path));
+
+               res->bus = 0;
+               res->lun = scsilun_to_int(&res->dev_lun);
+
+               if (res->type == IPR_RES_TYPE_GENERIC_SCSI) {
+                       list_for_each_entry(gscsi_res, &ioa_cfg->used_res_q, queue) {
+                               if (gscsi_res->dev_id == cfgtew->u.cfgte64->dev_id) {
+                                       found = 1;
+                                       res->target = gscsi_res->target;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               res->target = find_first_zero_bit(ioa_cfg->target_ids,
+                                                                 ioa_cfg->max_devs_supported);
+                               set_bit(res->target, ioa_cfg->target_ids);
+                       }
+
+                       memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
+                               sizeof(res->dev_lun.scsi_lun));
+               } else if (res->type == IPR_RES_TYPE_IOAFP) {
+                       res->bus = IPR_IOAFP_VIRTUAL_BUS;
+                       res->target = 0;
+               } else if (res->type == IPR_RES_TYPE_ARRAY) {
+                       res->bus = IPR_ARRAY_VIRTUAL_BUS;
+                       res->target = find_first_zero_bit(ioa_cfg->array_ids,
+                                                         ioa_cfg->max_devs_supported);
+                       set_bit(res->target, ioa_cfg->array_ids);
+               } else if (res->type == IPR_RES_TYPE_VOLUME_SET) {
+                       res->bus = IPR_VSET_VIRTUAL_BUS;
+                       res->target = find_first_zero_bit(ioa_cfg->vset_ids,
+                                                         ioa_cfg->max_devs_supported);
+                       set_bit(res->target, ioa_cfg->vset_ids);
+               } else {
+                       res->target = find_first_zero_bit(ioa_cfg->target_ids,
+                                                         ioa_cfg->max_devs_supported);
+                       set_bit(res->target, ioa_cfg->target_ids);
+               }
+       } else {
+               proto = cfgtew->u.cfgte->proto;
+               res->qmodel = IPR_QUEUEING_MODEL(res);
+               res->flags = cfgtew->u.cfgte->flags;
+               if (res->flags & IPR_IS_IOA_RESOURCE)
+                       res->type = IPR_RES_TYPE_IOAFP;
+               else
+                       res->type = cfgtew->u.cfgte->rsvd_subtype & 0x0f;
+
+               res->bus = cfgtew->u.cfgte->res_addr.bus;
+               res->target = cfgtew->u.cfgte->res_addr.target;
+               res->lun = cfgtew->u.cfgte->res_addr.lun;
+       }
+
+       ipr_update_ata_class(res, proto);
+}
+
+/**
+ * ipr_is_same_device - Determine if two devices are the same.
+ * @res:       resource entry struct
+ * @cfgtew:    config table entry wrapper struct
+ *
+ * Return value:
+ *     1 if the devices are the same / 0 otherwise
+ **/
+static int ipr_is_same_device(struct ipr_resource_entry *res,
+                             struct ipr_config_table_entry_wrapper *cfgtew)
+{
+       if (res->ioa_cfg->sis64) {
+               if (!memcmp(&res->dev_id, &cfgtew->u.cfgte64->dev_id,
+                                       sizeof(cfgtew->u.cfgte64->dev_id)) &&
+                       !memcmp(&res->lun, &cfgtew->u.cfgte64->lun,
+                                       sizeof(cfgtew->u.cfgte64->lun))) {
+                       return 1;
+               }
+       } else {
+               if (res->bus == cfgtew->u.cfgte->res_addr.bus &&
+                   res->target == cfgtew->u.cfgte->res_addr.target &&
+                   res->lun == cfgtew->u.cfgte->res_addr.lun)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * ipr_format_resource_path - Format the resource path for printing.
+ * @res_path:  resource path
+ * @buf:       buffer
+ *
+ * Return value:
+ *     pointer to buffer
+ **/
+static char *ipr_format_resource_path(u8 *res_path, char *buffer)
+{
+       int i;
+
+       sprintf(buffer, "%02X", res_path[0]);
+       for (i=1; res_path[i] != 0xff; i++)
+               sprintf(buffer, "%s-%02X", buffer, res_path[i]);
+
+       return buffer;
+}
+
+/**
+ * ipr_update_res_entry - Update the resource entry.
+ * @res:       resource entry struct
+ * @cfgtew:    config table entry wrapper struct
+ *
+ * Return value:
+ *      none
+ **/
+static void ipr_update_res_entry(struct ipr_resource_entry *res,
+                                struct ipr_config_table_entry_wrapper *cfgtew)
+{
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+       unsigned int proto;
+       int new_path = 0;
+
+       if (res->ioa_cfg->sis64) {
+               res->flags = cfgtew->u.cfgte64->flags;
+               res->res_flags = cfgtew->u.cfgte64->res_flags;
+               res->type = cfgtew->u.cfgte64->res_type & 0x0f;
+
+               memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data,
+                       sizeof(struct ipr_std_inq_data));
+
+               res->qmodel = IPR_QUEUEING_MODEL64(res);
+               proto = cfgtew->u.cfgte64->proto;
+               res->res_handle = cfgtew->u.cfgte64->res_handle;
+               res->dev_id = cfgtew->u.cfgte64->dev_id;
+
+               memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
+                       sizeof(res->dev_lun.scsi_lun));
+
+               if (memcmp(res->res_path, &cfgtew->u.cfgte64->res_path,
+                                       sizeof(res->res_path))) {
+                       memcpy(res->res_path, &cfgtew->u.cfgte64->res_path,
+                               sizeof(res->res_path));
+                       new_path = 1;
+               }
+
+               if (res->sdev && new_path)
+                       sdev_printk(KERN_INFO, res->sdev, "Resource path: %s\n",
+                                   ipr_format_resource_path(&res->res_path[0], &buffer[0]));
+       } else {
+               res->flags = cfgtew->u.cfgte->flags;
+               if (res->flags & IPR_IS_IOA_RESOURCE)
+                       res->type = IPR_RES_TYPE_IOAFP;
+               else
+                       res->type = cfgtew->u.cfgte->rsvd_subtype & 0x0f;
+
+               memcpy(&res->std_inq_data, &cfgtew->u.cfgte->std_inq_data,
+                       sizeof(struct ipr_std_inq_data));
+
+               res->qmodel = IPR_QUEUEING_MODEL(res);
+               proto = cfgtew->u.cfgte->proto;
+               res->res_handle = cfgtew->u.cfgte->res_handle;
+       }
+
+       ipr_update_ata_class(res, proto);
+}
+
+/**
+ * ipr_clear_res_target - Clear the bit in the bit map representing the target
+ *                       for the resource.
+ * @res:       resource entry struct
+ * @cfgtew:    config table entry wrapper struct
+ *
+ * Return value:
+ *      none
+ **/
+static void ipr_clear_res_target(struct ipr_resource_entry *res)
+{
+       struct ipr_resource_entry *gscsi_res = NULL;
+       struct ipr_ioa_cfg *ioa_cfg = res->ioa_cfg;
+
+       if (!ioa_cfg->sis64)
+               return;
+
+       if (res->bus == IPR_ARRAY_VIRTUAL_BUS)
+               clear_bit(res->target, ioa_cfg->array_ids);
+       else if (res->bus == IPR_VSET_VIRTUAL_BUS)
+               clear_bit(res->target, ioa_cfg->vset_ids);
+       else if (res->bus == 0 && res->type == IPR_RES_TYPE_GENERIC_SCSI) {
+               list_for_each_entry(gscsi_res, &ioa_cfg->used_res_q, queue)
+                       if (gscsi_res->dev_id == res->dev_id && gscsi_res != res)
+                               return;
+               clear_bit(res->target, ioa_cfg->target_ids);
+
+       } else if (res->bus == 0)
+               clear_bit(res->target, ioa_cfg->target_ids);
 }
 
 /**
@@ -851,17 +1244,24 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res)
  *     none
  **/
 static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,
-                             struct ipr_hostrcb *hostrcb)
+                                    struct ipr_hostrcb *hostrcb)
 {
        struct ipr_resource_entry *res = NULL;
-       struct ipr_config_table_entry *cfgte;
+       struct ipr_config_table_entry_wrapper cfgtew;
+       __be32 cc_res_handle;
+
        u32 is_ndn = 1;
 
-       cfgte = &hostrcb->hcam.u.ccn.cfgte;
+       if (ioa_cfg->sis64) {
+               cfgtew.u.cfgte64 = &hostrcb->hcam.u.ccn.u.cfgte64;
+               cc_res_handle = cfgtew.u.cfgte64->res_handle;
+       } else {
+               cfgtew.u.cfgte = &hostrcb->hcam.u.ccn.u.cfgte;
+               cc_res_handle = cfgtew.u.cfgte->res_handle;
+       }
 
        list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-               if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr,
-                           sizeof(cfgte->res_addr))) {
+               if (res->res_handle == cc_res_handle) {
                        is_ndn = 0;
                        break;
                }
@@ -879,20 +1279,22 @@ static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,
                                 struct ipr_resource_entry, queue);
 
                list_del(&res->queue);
-               ipr_init_res_entry(res);
+               ipr_init_res_entry(res, &cfgtew);
                list_add_tail(&res->queue, &ioa_cfg->used_res_q);
        }
 
-       memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));
+       ipr_update_res_entry(res, &cfgtew);
 
        if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {
                if (res->sdev) {
                        res->del_from_ml = 1;
-                       res->cfgte.res_handle = IPR_INVALID_RES_HANDLE;
+                       res->res_handle = IPR_INVALID_RES_HANDLE;
                        if (ioa_cfg->allow_ml_add_del)
                                schedule_work(&ioa_cfg->work_q);
-               } else
+               } else {
+                       ipr_clear_res_target(res);
                        list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+               }
        } else if (!res->sdev) {
                res->add_to_ml = 1;
                if (ioa_cfg->allow_ml_add_del)
@@ -1044,8 +1446,12 @@ static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd)
 static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg,
                                         struct ipr_hostrcb *hostrcb)
 {
-       struct ipr_hostrcb_type_12_error *error =
-               &hostrcb->hcam.u.error.u.type_12_error;
+       struct ipr_hostrcb_type_12_error *error;
+
+       if (ioa_cfg->sis64)
+               error = &hostrcb->hcam.u.error64.u.type_12_error;
+       else
+               error = &hostrcb->hcam.u.error.u.type_12_error;
 
        ipr_err("-----Current Configuration-----\n");
        ipr_err("Cache Directory Card Information:\n");
@@ -1138,6 +1544,48 @@ static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg,
 }
 
 /**
+ * ipr_log_sis64_config_error - Log a device error.
+ * @ioa_cfg:   ioa config struct
+ * @hostrcb:   hostrcb struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg,
+                                      struct ipr_hostrcb *hostrcb)
+{
+       int errors_logged, i;
+       struct ipr_hostrcb64_device_data_entry_enhanced *dev_entry;
+       struct ipr_hostrcb_type_23_error *error;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+       error = &hostrcb->hcam.u.error64.u.type_23_error;
+       errors_logged = be32_to_cpu(error->errors_logged);
+
+       ipr_err("Device Errors Detected/Logged: %d/%d\n",
+               be32_to_cpu(error->errors_detected), errors_logged);
+
+       dev_entry = error->dev;
+
+       for (i = 0; i < errors_logged; i++, dev_entry++) {
+               ipr_err_separator;
+
+               ipr_err("Device %d : %s", i + 1,
+                        ipr_format_resource_path(&dev_entry->res_path[0], &buffer[0]));
+               ipr_log_ext_vpd(&dev_entry->vpd);
+
+               ipr_err("-----New Device Information-----\n");
+               ipr_log_ext_vpd(&dev_entry->new_vpd);
+
+               ipr_err("Cache Directory Card Information:\n");
+               ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd);
+
+               ipr_err("Adapter Card Information:\n");
+               ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd);
+       }
+}
+
+/**
  * ipr_log_config_error - Log a configuration error.
  * @ioa_cfg:   ioa config struct
  * @hostrcb:   hostrcb struct
@@ -1331,7 +1779,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 {
        struct ipr_hostrcb_type_17_error *error;
 
-       error = &hostrcb->hcam.u.error.u.type_17_error;
+       if (ioa_cfg->sis64)
+               error = &hostrcb->hcam.u.error64.u.type_17_error;
+       else
+               error = &hostrcb->hcam.u.error.u.type_17_error;
+
        error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
        strim(error->failure_reason);
 
@@ -1438,6 +1890,42 @@ static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
                fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
 }
 
+/**
+ * ipr_log64_fabric_path - Log a fabric path error
+ * @hostrcb:   hostrcb struct
+ * @fabric:            fabric descriptor
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb,
+                                 struct ipr_hostrcb64_fabric_desc *fabric)
+{
+       int i, j;
+       u8 path_state = fabric->path_state;
+       u8 active = path_state & IPR_PATH_ACTIVE_MASK;
+       u8 state = path_state & IPR_PATH_STATE_MASK;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+       for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) {
+               if (path_active_desc[i].active != active)
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) {
+                       if (path_state_desc[j].state != state)
+                               continue;
+
+                       ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n",
+                                    path_active_desc[i].desc, path_state_desc[j].desc,
+                                    ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
+                       return;
+               }
+       }
+
+       ipr_err("Path state=%02X Resource Path=%s\n", path_state,
+               ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
+}
+
 static const struct {
        u8 type;
        char *desc;
@@ -1547,6 +2035,49 @@ static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
 }
 
 /**
+ * ipr_log64_path_elem - Log a fabric path element.
+ * @hostrcb:   hostrcb struct
+ * @cfg:               fabric path element struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb,
+                               struct ipr_hostrcb64_config_element *cfg)
+{
+       int i, j;
+       u8 desc_id = cfg->descriptor_id & IPR_DESCRIPTOR_MASK;
+       u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
+       u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+       if (type == IPR_PATH_CFG_NOT_EXIST || desc_id != IPR_DESCRIPTOR_SIS64)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) {
+               if (path_type_desc[i].type != type)
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) {
+                       if (path_status_desc[j].status != status)
+                               continue;
+
+                       ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n",
+                                    path_status_desc[j].desc, path_type_desc[i].desc,
+                                    ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
+                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                       return;
+               }
+       }
+       ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s "
+                    "WWN=%08X%08X\n", cfg->type_status,
+                    ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
+                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+}
+
+/**
  * ipr_log_fabric_error - Log a fabric error.
  * @ioa_cfg:   ioa config struct
  * @hostrcb:   hostrcb struct
@@ -1584,6 +2115,96 @@ static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
 }
 
 /**
+ * ipr_log_sis64_array_error - Log a sis64 array error.
+ * @ioa_cfg:   ioa config struct
+ * @hostrcb:   hostrcb struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg,
+                                     struct ipr_hostrcb *hostrcb)
+{
+       int i, num_entries;
+       struct ipr_hostrcb_type_24_error *error;
+       struct ipr_hostrcb64_array_data_entry *array_entry;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+       const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' };
+
+       error = &hostrcb->hcam.u.error64.u.type_24_error;
+
+       ipr_err_separator;
+
+       ipr_err("RAID %s Array Configuration: %s\n",
+               error->protection_level,
+               ipr_format_resource_path(&error->last_res_path[0], &buffer[0]));
+
+       ipr_err_separator;
+
+       array_entry = error->array_member;
+       num_entries = min_t(u32, be32_to_cpu(error->num_entries),
+                           sizeof(error->array_member));
+
+       for (i = 0; i < num_entries; i++, array_entry++) {
+
+               if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN))
+                       continue;
+
+               if (error->exposed_mode_adn == i)
+                       ipr_err("Exposed Array Member %d:\n", i);
+               else
+                       ipr_err("Array Member %d:\n", i);
+
+               ipr_err("Array Member %d:\n", i);
+               ipr_log_ext_vpd(&array_entry->vpd);
+               ipr_err("Current Location: %s",
+                        ipr_format_resource_path(&array_entry->res_path[0], &buffer[0]));
+               ipr_err("Expected Location: %s",
+                        ipr_format_resource_path(&array_entry->expected_res_path[0], &buffer[0]));
+
+               ipr_err_separator;
+       }
+}
+
+/**
+ * ipr_log_sis64_fabric_error - Log a sis64 fabric error.
+ * @ioa_cfg:   ioa config struct
+ * @hostrcb:   hostrcb struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_sis64_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
+                                      struct ipr_hostrcb *hostrcb)
+{
+       struct ipr_hostrcb_type_30_error *error;
+       struct ipr_hostrcb64_fabric_desc *fabric;
+       struct ipr_hostrcb64_config_element *cfg;
+       int i, add_len;
+
+       error = &hostrcb->hcam.u.error64.u.type_30_error;
+
+       error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       ipr_hcam_err(hostrcb, "%s\n", error->failure_reason);
+
+       add_len = be32_to_cpu(hostrcb->hcam.length) -
+               (offsetof(struct ipr_hostrcb64_error, u) +
+                offsetof(struct ipr_hostrcb_type_30_error, desc));
+
+       for (i = 0, fabric = error->desc; i < error->num_entries; i++) {
+               ipr_log64_fabric_path(hostrcb, fabric);
+               for_each_fabric_cfg(fabric, cfg)
+                       ipr_log64_path_elem(hostrcb, cfg);
+
+               add_len -= be16_to_cpu(fabric->length);
+               fabric = (struct ipr_hostrcb64_fabric_desc *)
+                       ((unsigned long)fabric + be16_to_cpu(fabric->length));
+       }
+
+       ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
+}
+
+/**
  * ipr_log_generic_error - Log an adapter error.
  * @ioa_cfg:   ioa config struct
  * @hostrcb:   hostrcb struct
@@ -1642,13 +2263,16 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
        if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)
                dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n");
 
-       ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+       if (ioa_cfg->sis64)
+               ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
+       else
+               ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
 
-       if (ioasc == IPR_IOASC_BUS_WAS_RESET ||
-           ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) {
+       if (!ioa_cfg->sis64 && (ioasc == IPR_IOASC_BUS_WAS_RESET ||
+           ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER)) {
                /* Tell the midlayer we had a bus reset so it will handle the UA properly */
                scsi_report_bus_reset(ioa_cfg->host,
-                                     hostrcb->hcam.u.error.failing_dev_res_addr.bus);
+                                     hostrcb->hcam.u.error.fd_res_addr.bus);
        }
 
        error_index = ipr_get_error(ioasc);
@@ -1696,6 +2320,16 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
        case IPR_HOST_RCB_OVERLAY_ID_20:
                ipr_log_fabric_error(ioa_cfg, hostrcb);
                break;
+       case IPR_HOST_RCB_OVERLAY_ID_23:
+               ipr_log_sis64_config_error(ioa_cfg, hostrcb);
+               break;
+       case IPR_HOST_RCB_OVERLAY_ID_24:
+       case IPR_HOST_RCB_OVERLAY_ID_26:
+               ipr_log_sis64_array_error(ioa_cfg, hostrcb);
+               break;
+       case IPR_HOST_RCB_OVERLAY_ID_30:
+               ipr_log_sis64_fabric_error(ioa_cfg, hostrcb);
+               break;
        case IPR_HOST_RCB_OVERLAY_ID_1:
        case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
        default:
@@ -1720,7 +2354,12 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
-       u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+       u32 fd_ioasc;
+
+       if (ioa_cfg->sis64)
+               fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
+       else
+               fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
 
        list_del(&hostrcb->queue);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
@@ -1845,12 +2484,14 @@ static const struct ipr_ses_table_entry *
 ipr_find_ses_entry(struct ipr_resource_entry *res)
 {
        int i, j, matches;
+       struct ipr_std_inq_vpids *vpids;
        const struct ipr_ses_table_entry *ste = ipr_ses_table;
 
        for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) {
                for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) {
                        if (ste->compare_product_id_byte[j] == 'X') {
-                               if (res->cfgte.std_inq_data.vpids.product_id[j] == ste->product_id[j])
+                               vpids = &res->std_inq_data.vpids;
+                               if (vpids->product_id[j] == ste->product_id[j])
                                        matches++;
                                else
                                        break;
@@ -1885,10 +2526,10 @@ static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_wi
 
        /* Loop through each config table entry in the config table buffer */
        list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-               if (!(IPR_IS_SES_DEVICE(res->cfgte.std_inq_data)))
+               if (!(IPR_IS_SES_DEVICE(res->std_inq_data)))
                        continue;
 
-               if (bus != res->cfgte.res_addr.bus)
+               if (bus != res->bus)
                        continue;
 
                if (!(ste = ipr_find_ses_entry(res)))
@@ -1934,6 +2575,31 @@ static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay)
 }
 
 /**
+ * ipr_get_sis64_dump_data_section - Dump IOA memory
+ * @ioa_cfg:                   ioa config struct
+ * @start_addr:                        adapter address to dump
+ * @dest:                      destination kernel buffer
+ * @length_in_words:           length to dump in 4 byte words
+ *
+ * Return value:
+ *     0 on success
+ **/
+static int ipr_get_sis64_dump_data_section(struct ipr_ioa_cfg *ioa_cfg,
+                                          u32 start_addr,
+                                          __be32 *dest, u32 length_in_words)
+{
+       int i;
+
+       for (i = 0; i < length_in_words; i++) {
+               writel(start_addr+(i*4), ioa_cfg->regs.dump_addr_reg);
+               *dest = cpu_to_be32(readl(ioa_cfg->regs.dump_data_reg));
+               dest++;
+       }
+
+       return 0;
+}
+
+/**
  * ipr_get_ldump_data_section - Dump IOA memory
  * @ioa_cfg:                   ioa config struct
  * @start_addr:                        adapter address to dump
@@ -1950,9 +2616,13 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
        volatile u32 temp_pcii_reg;
        int i, delay = 0;
 
+       if (ioa_cfg->sis64)
+               return ipr_get_sis64_dump_data_section(ioa_cfg, start_addr,
+                                                      dest, length_in_words);
+
        /* Write IOA interrupt reg starting LDUMP state  */
        writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT),
-              ioa_cfg->regs.set_uproc_interrupt_reg);
+              ioa_cfg->regs.set_uproc_interrupt_reg32);
 
        /* Wait for IO debug acknowledge */
        if (ipr_wait_iodbg_ack(ioa_cfg,
@@ -1971,7 +2641,7 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
 
        /* Signal address valid - clear IOA Reset alert */
        writel(IPR_UPROCI_RESET_ALERT,
-              ioa_cfg->regs.clr_uproc_interrupt_reg);
+              ioa_cfg->regs.clr_uproc_interrupt_reg32);
 
        for (i = 0; i < length_in_words; i++) {
                /* Wait for IO debug acknowledge */
@@ -1996,10 +2666,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
 
        /* Signal end of block transfer. Set reset alert then clear IO debug ack */
        writel(IPR_UPROCI_RESET_ALERT,
-              ioa_cfg->regs.set_uproc_interrupt_reg);
+              ioa_cfg->regs.set_uproc_interrupt_reg32);
 
        writel(IPR_UPROCI_IO_DEBUG_ALERT,
-              ioa_cfg->regs.clr_uproc_interrupt_reg);
+              ioa_cfg->regs.clr_uproc_interrupt_reg32);
 
        /* Signal dump data received - Clear IO debug Ack */
        writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,
@@ -2008,7 +2678,7 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
        /* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */
        while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) {
                temp_pcii_reg =
-                   readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
+                   readl(ioa_cfg->regs.sense_uproc_interrupt_reg32);
 
                if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT))
                        return 0;
@@ -2207,6 +2877,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
        u32 num_entries, start_off, end_off;
        u32 bytes_to_copy, bytes_copied, rc;
        struct ipr_sdt *sdt;
+       int valid = 1;
        int i;
 
        ENTER;
@@ -2220,7 +2891,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
 
        start_addr = readl(ioa_cfg->ioa_mailbox);
 
-       if (!ipr_sdt_is_fmt2(start_addr)) {
+       if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) {
                dev_err(&ioa_cfg->pdev->dev,
                        "Invalid dump table format: %lx\n", start_addr);
                spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -2249,7 +2920,6 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
 
        /* IOA Dump entry */
        ipr_init_dump_entry_hdr(&ioa_dump->hdr);
-       ioa_dump->format = IPR_SDT_FMT2;
        ioa_dump->hdr.len = 0;
        ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;
        ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID;
@@ -2264,7 +2934,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
                                        sizeof(struct ipr_sdt) / sizeof(__be32));
 
        /* Smart Dump table is ready to use and the first entry is valid */
-       if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) {
+       if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) &&
+           (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) {
                dev_err(&ioa_cfg->pdev->dev,
                        "Dump of IOA failed. Dump table not valid: %d, %X.\n",
                        rc, be32_to_cpu(sdt->hdr.state));
@@ -2288,12 +2959,19 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
                }
 
                if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) {
-                       sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset);
-                       start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK;
-                       end_off = be32_to_cpu(sdt->entry[i].end_offset);
-
-                       if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) {
-                               bytes_to_copy = end_off - start_off;
+                       sdt_word = be32_to_cpu(sdt->entry[i].start_token);
+                       if (ioa_cfg->sis64)
+                               bytes_to_copy = be32_to_cpu(sdt->entry[i].end_token);
+                       else {
+                               start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK;
+                               end_off = be32_to_cpu(sdt->entry[i].end_token);
+
+                               if (ipr_sdt_is_fmt2(sdt_word) && sdt_word)
+                                       bytes_to_copy = end_off - start_off;
+                               else
+                                       valid = 0;
+                       }
+                       if (valid) {
                                if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) {
                                        sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY;
                                        continue;
@@ -2422,9 +3100,9 @@ restart:
 
        list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
                if (res->add_to_ml) {
-                       bus = res->cfgte.res_addr.bus;
-                       target = res->cfgte.res_addr.target;
-                       lun = res->cfgte.res_addr.lun;
+                       bus = res->bus;
+                       target = res->target;
+                       lun = res->lun;
                        res->add_to_ml = 0;
                        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
                        scsi_add_device(ioa_cfg->host, bus, target, lun);
@@ -2478,105 +3156,6 @@ static struct bin_attribute ipr_trace_attr = {
 };
 #endif
 
-static const struct {
-       enum ipr_cache_state state;
-       char *name;
-} cache_state [] = {
-       { CACHE_NONE, "none" },
-       { CACHE_DISABLED, "disabled" },
-       { CACHE_ENABLED, "enabled" }
-};
-
-/**
- * ipr_show_write_caching - Show the write caching attribute
- * @dev:       device struct
- * @buf:       buffer
- *
- * Return value:
- *     number of bytes printed to buffer
- **/
-static ssize_t ipr_show_write_caching(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
-       unsigned long lock_flags = 0;
-       int i, len = 0;
-
-       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-       for (i = 0; i < ARRAY_SIZE(cache_state); i++) {
-               if (cache_state[i].state == ioa_cfg->cache_state) {
-                       len = snprintf(buf, PAGE_SIZE, "%s\n", cache_state[i].name);
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-       return len;
-}
-
-
-/**
- * ipr_store_write_caching - Enable/disable adapter write cache
- * @dev:       device struct
- * @buf:       buffer
- * @count:     buffer size
- *
- * This function will enable/disable adapter write cache.
- *
- * Return value:
- *     count on success / other on failure
- **/
-static ssize_t ipr_store_write_caching(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
-       unsigned long lock_flags = 0;
-       enum ipr_cache_state new_state = CACHE_INVALID;
-       int i;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-       if (ioa_cfg->cache_state == CACHE_NONE)
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(cache_state); i++) {
-               if (!strncmp(cache_state[i].name, buf, strlen(cache_state[i].name))) {
-                       new_state = cache_state[i].state;
-                       break;
-               }
-       }
-
-       if (new_state != CACHE_DISABLED && new_state != CACHE_ENABLED)
-               return -EINVAL;
-
-       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-       if (ioa_cfg->cache_state == new_state) {
-               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-               return count;
-       }
-
-       ioa_cfg->cache_state = new_state;
-       dev_info(&ioa_cfg->pdev->dev, "%s adapter write cache.\n",
-                new_state == CACHE_ENABLED ? "Enabling" : "Disabling");
-       if (!ioa_cfg->in_reset_reload)
-               ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
-       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-       wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
-
-       return count;
-}
-
-static struct device_attribute ipr_ioa_cache_attr = {
-       .attr = {
-               .name =         "write_cache",
-               .mode =         S_IRUGO | S_IWUSR,
-       },
-       .show = ipr_show_write_caching,
-       .store = ipr_store_write_caching
-};
-
 /**
  * ipr_show_fw_version - Show the firmware version
  * @dev:       class device struct
@@ -2976,6 +3555,37 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
 }
 
 /**
+ * ipr_build_ucode_ioadl64 - Build a microcode download IOADL
+ * @ipr_cmd:           ipr command struct
+ * @sglist:            scatter/gather list
+ *
+ * Builds a microcode download IOA data list (IOADL).
+ *
+ **/
+static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
+                                   struct ipr_sglist *sglist)
+{
+       struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+       struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
+       struct scatterlist *scatterlist = sglist->scatterlist;
+       int i;
+
+       ipr_cmd->dma_use_sg = sglist->num_dma_sg;
+       ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+       ioarcb->data_transfer_length = cpu_to_be32(sglist->buffer_len);
+
+       ioarcb->ioadl_len =
+               cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
+       for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+               ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE);
+               ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i]));
+               ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i]));
+       }
+
+       ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+}
+
+/**
  * ipr_build_ucode_ioadl - Build a microcode download IOADL
  * @ipr_cmd:   ipr command struct
  * @sglist:            scatter/gather list
@@ -2987,14 +3597,15 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
                                  struct ipr_sglist *sglist)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+       struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
        struct scatterlist *scatterlist = sglist->scatterlist;
        int i;
 
        ipr_cmd->dma_use_sg = sglist->num_dma_sg;
        ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
-       ioarcb->write_data_transfer_length = cpu_to_be32(sglist->buffer_len);
-       ioarcb->write_ioadl_len =
+       ioarcb->data_transfer_length = cpu_to_be32(sglist->buffer_len);
+
+       ioarcb->ioadl_len =
                cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
 
        for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
@@ -3146,7 +3757,6 @@ static struct device_attribute *ipr_ioa_attrs[] = {
        &ipr_ioa_state_attr,
        &ipr_ioa_reset_attr,
        &ipr_update_fw_attr,
-       &ipr_ioa_cache_attr,
        NULL,
 };
 
@@ -3450,7 +4060,7 @@ static ssize_t ipr_show_adapter_handle(struct device *dev, struct device_attribu
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
        res = (struct ipr_resource_entry *)sdev->hostdata;
        if (res)
-               len = snprintf(buf, PAGE_SIZE, "%08X\n", res->cfgte.res_handle);
+               len = snprintf(buf, PAGE_SIZE, "%08X\n", res->res_handle);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        return len;
 }
@@ -3463,8 +4073,43 @@ static struct device_attribute ipr_adapter_handle_attr = {
        .show = ipr_show_adapter_handle
 };
 
+/**
+ * ipr_show_resource_path - Show the resource path for this device.
+ * @dev:       device struct
+ * @buf:       buffer
+ *
+ * Return value:
+ *     number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+       struct ipr_resource_entry *res;
+       unsigned long lock_flags = 0;
+       ssize_t len = -ENXIO;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       res = (struct ipr_resource_entry *)sdev->hostdata;
+       if (res)
+               len = snprintf(buf, PAGE_SIZE, "%s\n",
+                              ipr_format_resource_path(&res->res_path[0], &buffer[0]));
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       return len;
+}
+
+static struct device_attribute ipr_resource_path_attr = {
+       .attr = {
+               .name =         "resource_path",
+               .mode =         S_IRUSR,
+       },
+       .show = ipr_show_resource_path
+};
+
 static struct device_attribute *ipr_dev_attrs[] = {
        &ipr_adapter_handle_attr,
+       &ipr_resource_path_attr,
        NULL,
 };
 
@@ -3517,9 +4162,9 @@ static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
        struct ipr_resource_entry *res;
 
        list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-               if ((res->cfgte.res_addr.bus == starget->channel) &&
-                   (res->cfgte.res_addr.target == starget->id) &&
-                   (res->cfgte.res_addr.lun == 0)) {
+               if ((res->bus == starget->channel) &&
+                   (res->target == starget->id) &&
+                   (res->lun == 0)) {
                        return res;
                }
        }
@@ -3589,6 +4234,17 @@ static int ipr_target_alloc(struct scsi_target *starget)
 static void ipr_target_destroy(struct scsi_target *starget)
 {
        struct ipr_sata_port *sata_port = starget->hostdata;
+       struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+       struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
+
+       if (ioa_cfg->sis64) {
+               if (starget->channel == IPR_ARRAY_VIRTUAL_BUS)
+                       clear_bit(starget->id, ioa_cfg->array_ids);
+               else if (starget->channel == IPR_VSET_VIRTUAL_BUS)
+                       clear_bit(starget->id, ioa_cfg->vset_ids);
+               else if (starget->channel == 0)
+                       clear_bit(starget->id, ioa_cfg->target_ids);
+       }
 
        if (sata_port) {
                starget->hostdata = NULL;
@@ -3610,9 +4266,9 @@ static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
        struct ipr_resource_entry *res;
 
        list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-               if ((res->cfgte.res_addr.bus == sdev->channel) &&
-                   (res->cfgte.res_addr.target == sdev->id) &&
-                   (res->cfgte.res_addr.lun == sdev->lun))
+               if ((res->bus == sdev->channel) &&
+                   (res->target == sdev->id) &&
+                   (res->lun == sdev->lun))
                        return res;
        }
 
@@ -3661,6 +4317,7 @@ static int ipr_slave_configure(struct scsi_device *sdev)
        struct ipr_resource_entry *res;
        struct ata_port *ap = NULL;
        unsigned long lock_flags = 0;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
        res = sdev->hostdata;
@@ -3687,6 +4344,9 @@ static int ipr_slave_configure(struct scsi_device *sdev)
                        ata_sas_slave_configure(sdev, ap);
                } else
                        scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+               if (ioa_cfg->sis64)
+                       sdev_printk(KERN_INFO, sdev, "Resource path: %s\n",
+                                   ipr_format_resource_path(&res->res_path[0], &buffer[0]));
                return 0;
        }
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -3828,14 +4488,19 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
        ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
        ioarcb = &ipr_cmd->ioarcb;
        cmd_pkt = &ioarcb->cmd_pkt;
-       regs = &ioarcb->add_data.u.regs;
 
-       ioarcb->res_handle = res->cfgte.res_handle;
+       if (ipr_cmd->ioa_cfg->sis64) {
+               regs = &ipr_cmd->i.ata_ioadl.regs;
+               ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb));
+       } else
+               regs = &ioarcb->u.add_data.u.regs;
+
+       ioarcb->res_handle = res->res_handle;
        cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
        cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
        if (ipr_is_gata(res)) {
                cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET;
-               ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags));
+               ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(regs->flags));
                regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
        }
 
@@ -3880,19 +4545,7 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
        res = sata_port->res;
        if (res) {
                rc = ipr_device_reset(ioa_cfg, res);
-               switch(res->cfgte.proto) {
-               case IPR_PROTO_SATA:
-               case IPR_PROTO_SAS_STP:
-                       *classes = ATA_DEV_ATA;
-                       break;
-               case IPR_PROTO_SATA_ATAPI:
-               case IPR_PROTO_SAS_STP_ATAPI:
-                       *classes = ATA_DEV_ATAPI;
-                       break;
-               default:
-                       *classes = ATA_DEV_UNKNOWN;
-                       break;
-               };
+               *classes = res->ata_class;
        }
 
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -3937,7 +4590,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
                return FAILED;
 
        list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-               if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
+               if (ipr_cmd->ioarcb.res_handle == res->res_handle) {
                        if (ipr_cmd->scsi_cmd)
                                ipr_cmd->done = ipr_scsi_eh_done;
                        if (ipr_cmd->qc)
@@ -3959,7 +4612,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
                spin_lock_irq(scsi_cmd->device->host->host_lock);
 
                list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-                       if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
+                       if (ipr_cmd->ioarcb.res_handle == res->res_handle) {
                                rc = -EIO;
                                break;
                        }
@@ -3998,13 +4651,13 @@ static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd)
        struct ipr_resource_entry *res;
 
        ENTER;
-       list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-               if (!memcmp(&res->cfgte.res_handle, &ipr_cmd->ioarcb.res_handle,
-                           sizeof(res->cfgte.res_handle))) {
-                       scsi_report_bus_reset(ioa_cfg->host, res->cfgte.res_addr.bus);
-                       break;
+       if (!ioa_cfg->sis64)
+               list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+                       if (res->res_handle == ipr_cmd->ioarcb.res_handle) {
+                               scsi_report_bus_reset(ioa_cfg->host, res->bus);
+                               break;
+                       }
                }
-       }
 
        /*
         * If abort has not completed, indicate the reset has, else call the
@@ -4102,7 +4755,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
                return SUCCESS;
 
        ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
-       ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+       ipr_cmd->ioarcb.res_handle = res->res_handle;
        cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
        cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
        cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS;
@@ -4239,11 +4892,29 @@ static irqreturn_t ipr_isr(int irq, void *devp)
                return IRQ_NONE;
        }
 
-       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
-       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
+       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
 
-       /* If an interrupt on the adapter did not occur, ignore it */
+       /* If an interrupt on the adapter did not occur, ignore it.
+        * Or in the case of SIS 64, check for a stage change interrupt.
+        */
        if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
+               if (ioa_cfg->sis64) {
+                       int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+                       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+                       if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
+
+                               /* clear stage change */
+                               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
+                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+                               list_del(&ioa_cfg->reset_cmd->queue);
+                               del_timer(&ioa_cfg->reset_cmd->timer);
+                               ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+                               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+                               return IRQ_HANDLED;
+                       }
+               }
+
                spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
                return IRQ_NONE;
        }
@@ -4286,8 +4957,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
                if (ipr_cmd != NULL) {
                        /* Clear the PCI interrupt */
                        do {
-                               writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
-                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+                               writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
+                               int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
                        } while (int_reg & IPR_PCII_HRRQ_UPDATED &&
                                        num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
 
@@ -4309,6 +4980,53 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 }
 
 /**
+ * ipr_build_ioadl64 - Build a scatter/gather list and map the buffer
+ * @ioa_cfg:   ioa config struct
+ * @ipr_cmd:   ipr command struct
+ *
+ * Return value:
+ *     0 on success / -1 on failure
+ **/
+static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg,
+                            struct ipr_cmnd *ipr_cmd)
+{
+       int i, nseg;
+       struct scatterlist *sg;
+       u32 length;
+       u32 ioadl_flags = 0;
+       struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+       struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+       struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
+
+       length = scsi_bufflen(scsi_cmd);
+       if (!length)
+               return 0;
+
+       nseg = scsi_dma_map(scsi_cmd);
+       if (nseg < 0) {
+               dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+               return -1;
+       }
+
+       ipr_cmd->dma_use_sg = nseg;
+
+       if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
+               ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+               ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+       } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE)
+               ioadl_flags = IPR_IOADL_FLAGS_READ;
+
+       scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) {
+               ioadl64[i].flags = cpu_to_be32(ioadl_flags);
+               ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg));
+               ioadl64[i].address = cpu_to_be64(sg_dma_address(sg));
+       }
+
+       ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+       return 0;
+}
+
+/**
  * ipr_build_ioadl - Build a scatter/gather list and map the buffer
  * @ioa_cfg:   ioa config struct
  * @ipr_cmd:   ipr command struct
@@ -4325,7 +5043,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
        u32 ioadl_flags = 0;
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+       struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
 
        length = scsi_bufflen(scsi_cmd);
        if (!length)
@@ -4342,8 +5060,8 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
        if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
                ioadl_flags = IPR_IOADL_FLAGS_WRITE;
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
-               ioarcb->write_data_transfer_length = cpu_to_be32(length);
-               ioarcb->write_ioadl_len =
+               ioarcb->data_transfer_length = cpu_to_be32(length);
+               ioarcb->ioadl_len =
                        cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
        } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
                ioadl_flags = IPR_IOADL_FLAGS_READ;
@@ -4352,11 +5070,10 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
                        cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
        }
 
-       if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
-               ioadl = ioarcb->add_data.u.ioadl;
-               ioarcb->write_ioadl_addr =
-                       cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
-                                   offsetof(struct ipr_ioarcb, add_data));
+       if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->u.add_data.u.ioadl)) {
+               ioadl = ioarcb->u.add_data.u.ioadl;
+               ioarcb->write_ioadl_addr = cpu_to_be32((ipr_cmd->dma_addr) +
+                                   offsetof(struct ipr_ioarcb, u.add_data));
                ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
        }
 
@@ -4446,18 +5163,24 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
-       dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
+       dma_addr_t dma_addr = ipr_cmd->dma_addr;
 
        memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
-       ioarcb->write_data_transfer_length = 0;
+       ioarcb->data_transfer_length = 0;
        ioarcb->read_data_transfer_length = 0;
-       ioarcb->write_ioadl_len = 0;
+       ioarcb->ioadl_len = 0;
        ioarcb->read_ioadl_len = 0;
        ioasa->ioasc = 0;
        ioasa->residual_data_len = 0;
-       ioarcb->write_ioadl_addr =
-               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
-       ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+
+       if (ipr_cmd->ioa_cfg->sis64)
+               ioarcb->u.sis64_addr_data.data_ioadl_addr =
+                       cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
+       else {
+               ioarcb->write_ioadl_addr =
+                       cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
+               ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+       }
 }
 
 /**
@@ -4489,15 +5212,8 @@ static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
        cmd_pkt->flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
        cmd_pkt->timeout = cpu_to_be16(IPR_REQUEST_SENSE_TIMEOUT / HZ);
 
-       ipr_cmd->ioadl[0].flags_and_data_len =
-               cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | SCSI_SENSE_BUFFERSIZE);
-       ipr_cmd->ioadl[0].address =
-               cpu_to_be32(ipr_cmd->sense_buffer_dma);
-
-       ipr_cmd->ioarcb.read_ioadl_len =
-               cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-       ipr_cmd->ioarcb.read_data_transfer_length =
-               cpu_to_be32(SCSI_SENSE_BUFFERSIZE);
+       ipr_init_ioadl(ipr_cmd, ipr_cmd->sense_buffer_dma,
+                      SCSI_SENSE_BUFFERSIZE, IPR_IOADL_FLAGS_READ_LAST);
 
        ipr_do_req(ipr_cmd, ipr_erp_done, ipr_timeout,
                   IPR_REQUEST_SENSE_TIMEOUT * 2);
@@ -4893,9 +5609,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
 
        memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
        ipr_cmd->scsi_cmd = scsi_cmd;
-       ioarcb->res_handle = res->cfgte.res_handle;
+       ioarcb->res_handle = res->res_handle;
        ipr_cmd->done = ipr_scsi_done;
-       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
 
        if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
                if (scsi_cmd->underflow == 0)
@@ -4916,13 +5632,16 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
            (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE))
                ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
 
-       if (likely(rc == 0))
-               rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
+       if (likely(rc == 0)) {
+               if (ioa_cfg->sis64)
+                       rc = ipr_build_ioadl64(ioa_cfg, ipr_cmd);
+               else
+                       rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
+       }
 
        if (likely(rc == 0)) {
                mb();
-               writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
-                      ioa_cfg->regs.ioarrin_reg);
+               ipr_send_command(ipr_cmd);
        } else {
                 list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
                 return SCSI_MLQUEUE_HOST_BUSY;
@@ -5035,20 +5754,9 @@ static void ipr_ata_phy_reset(struct ata_port *ap)
                goto out_unlock;
        }
 
-       switch(res->cfgte.proto) {
-       case IPR_PROTO_SATA:
-       case IPR_PROTO_SAS_STP:
-               ap->link.device[0].class = ATA_DEV_ATA;
-               break;
-       case IPR_PROTO_SATA_ATAPI:
-       case IPR_PROTO_SAS_STP_ATAPI:
-               ap->link.device[0].class = ATA_DEV_ATAPI;
-               break;
-       default:
-               ap->link.device[0].class = ATA_DEV_UNKNOWN;
+       ap->link.device[0].class = res->ata_class;
+       if (ap->link.device[0].class == ATA_DEV_UNKNOWN)
                ata_port_disable(ap);
-               break;
-       };
 
 out_unlock:
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
@@ -5134,8 +5842,7 @@ static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
        ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
        if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
-               scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
-                                        res->cfgte.res_addr.target);
+               scsi_report_device_reset(ioa_cfg->host, res->bus, res->target);
 
        if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
                qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
@@ -5146,6 +5853,52 @@ static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
 }
 
 /**
+ * ipr_build_ata_ioadl64 - Build an ATA scatter/gather list
+ * @ipr_cmd:   ipr command struct
+ * @qc:                ATA queued command
+ *
+ **/
+static void ipr_build_ata_ioadl64(struct ipr_cmnd *ipr_cmd,
+                                 struct ata_queued_cmd *qc)
+{
+       u32 ioadl_flags = 0;
+       struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+       struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
+       struct ipr_ioadl64_desc *last_ioadl64 = NULL;
+       int len = qc->nbytes;
+       struct scatterlist *sg;
+       unsigned int si;
+       dma_addr_t dma_addr = ipr_cmd->dma_addr;
+
+       if (len == 0)
+               return;
+
+       if (qc->dma_dir == DMA_TO_DEVICE) {
+               ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+               ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+       } else if (qc->dma_dir == DMA_FROM_DEVICE)
+               ioadl_flags = IPR_IOADL_FLAGS_READ;
+
+       ioarcb->data_transfer_length = cpu_to_be32(len);
+       ioarcb->ioadl_len =
+               cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
+       ioarcb->u.sis64_addr_data.data_ioadl_addr =
+               cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ata_ioadl));
+
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               ioadl64->flags = cpu_to_be32(ioadl_flags);
+               ioadl64->data_len = cpu_to_be32(sg_dma_len(sg));
+               ioadl64->address = cpu_to_be64(sg_dma_address(sg));
+
+               last_ioadl64 = ioadl64;
+               ioadl64++;
+       }
+
+       if (likely(last_ioadl64))
+               last_ioadl64->flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+}
+
+/**
  * ipr_build_ata_ioadl - Build an ATA scatter/gather list
  * @ipr_cmd:   ipr command struct
  * @qc:                ATA queued command
@@ -5156,7 +5909,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
 {
        u32 ioadl_flags = 0;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+       struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
        struct ipr_ioadl_desc *last_ioadl = NULL;
        int len = qc->nbytes;
        struct scatterlist *sg;
@@ -5168,8 +5921,8 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
        if (qc->dma_dir == DMA_TO_DEVICE) {
                ioadl_flags = IPR_IOADL_FLAGS_WRITE;
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
-               ioarcb->write_data_transfer_length = cpu_to_be32(len);
-               ioarcb->write_ioadl_len =
+               ioarcb->data_transfer_length = cpu_to_be32(len);
+               ioarcb->ioadl_len =
                        cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
        } else if (qc->dma_dir == DMA_FROM_DEVICE) {
                ioadl_flags = IPR_IOADL_FLAGS_READ;
@@ -5212,25 +5965,34 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
 
        ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
        ioarcb = &ipr_cmd->ioarcb;
-       regs = &ioarcb->add_data.u.regs;
 
-       memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
-       ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
+       if (ioa_cfg->sis64) {
+               regs = &ipr_cmd->i.ata_ioadl.regs;
+               ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb));
+       } else
+               regs = &ioarcb->u.add_data.u.regs;
+
+       memset(regs, 0, sizeof(*regs));
+       ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(*regs));
 
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
        ipr_cmd->qc = qc;
        ipr_cmd->done = ipr_sata_done;
-       ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+       ipr_cmd->ioarcb.res_handle = res->res_handle;
        ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
        ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
        ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
        ipr_cmd->dma_use_sg = qc->n_elem;
 
-       ipr_build_ata_ioadl(ipr_cmd, qc);
+       if (ioa_cfg->sis64)
+               ipr_build_ata_ioadl64(ipr_cmd, qc);
+       else
+               ipr_build_ata_ioadl(ipr_cmd, qc);
+
        regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
        ipr_copy_sata_tf(regs, &qc->tf);
        memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN);
-       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
 
        switch (qc->tf.protocol) {
        case ATA_PROT_NODATA:
@@ -5257,8 +6019,9 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
        }
 
        mb();
-       writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
-              ioa_cfg->regs.ioarrin_reg);
+
+       ipr_send_command(ipr_cmd);
+
        return 0;
 }
 
@@ -5459,7 +6222,7 @@ static void ipr_set_sup_dev_dflt(struct ipr_supported_device *supported_dev,
  * ipr_set_supported_devs - Send Set Supported Devices for a device
  * @ipr_cmd:   ipr command struct
  *
- * This function send a Set Supported Devices to the adapter
+ * This function sends a Set Supported Devices to the adapter
  *
  * Return value:
  *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
@@ -5468,7 +6231,6 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_resource_entry *res = ipr_cmd->u.res;
 
@@ -5479,28 +6241,28 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd)
                        continue;
 
                ipr_cmd->u.res = res;
-               ipr_set_sup_dev_dflt(supp_dev, &res->cfgte.std_inq_data.vpids);
+               ipr_set_sup_dev_dflt(supp_dev, &res->std_inq_data.vpids);
 
                ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
                ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
 
                ioarcb->cmd_pkt.cdb[0] = IPR_SET_SUPPORTED_DEVICES;
+               ioarcb->cmd_pkt.cdb[1] = IPR_SET_ALL_SUPPORTED_DEVICES;
                ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_supported_device) >> 8) & 0xff;
                ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_supported_device) & 0xff;
 
-               ioadl->flags_and_data_len = cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST |
-                                                       sizeof(struct ipr_supported_device));
-               ioadl->address = cpu_to_be32(ioa_cfg->vpd_cbs_dma +
-                                            offsetof(struct ipr_misc_cbs, supp_dev));
-               ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-               ioarcb->write_data_transfer_length =
-                       cpu_to_be32(sizeof(struct ipr_supported_device));
+               ipr_init_ioadl(ipr_cmd,
+                              ioa_cfg->vpd_cbs_dma +
+                                offsetof(struct ipr_misc_cbs, supp_dev),
+                              sizeof(struct ipr_supported_device),
+                              IPR_IOADL_FLAGS_WRITE_LAST);
 
                ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
                           IPR_SET_SUP_DEVICE_TIMEOUT);
 
-               ipr_cmd->job_step = ipr_set_supported_devs;
+               if (!ioa_cfg->sis64)
+                       ipr_cmd->job_step = ipr_set_supported_devs;
                return IPR_RC_JOB_RETURN;
        }
 
@@ -5508,36 +6270,6 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd)
 }
 
 /**
- * ipr_setup_write_cache - Disable write cache if needed
- * @ipr_cmd:   ipr command struct
- *
- * This function sets up adapters write cache to desired setting
- *
- * Return value:
- *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
- **/
-static int ipr_setup_write_cache(struct ipr_cmnd *ipr_cmd)
-{
-       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-
-       ipr_cmd->job_step = ipr_set_supported_devs;
-       ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
-                                   struct ipr_resource_entry, queue);
-
-       if (ioa_cfg->cache_state != CACHE_DISABLED)
-               return IPR_RC_JOB_CONTINUE;
-
-       ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
-       ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
-       ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
-       ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_SHUTDOWN_PREPARE_FOR_NORMAL;
-
-       ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
-
-       return IPR_RC_JOB_RETURN;
-}
-
-/**
  * ipr_get_mode_page - Locate specified mode page
  * @mode_pages:        mode page buffer
  * @page_code: page code to find
@@ -5695,10 +6427,9 @@ static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg,
  *     none
  **/
 static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd,
-                                 __be32 res_handle, u8 parm, u32 dma_addr,
-                                 u8 xfer_len)
+                                 __be32 res_handle, u8 parm,
+                                 dma_addr_t dma_addr, u8 xfer_len)
 {
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
 
        ioarcb->res_handle = res_handle;
@@ -5708,11 +6439,7 @@ static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd,
        ioarcb->cmd_pkt.cdb[1] = parm;
        ioarcb->cmd_pkt.cdb[4] = xfer_len;
 
-       ioadl->flags_and_data_len =
-               cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | xfer_len);
-       ioadl->address = cpu_to_be32(dma_addr);
-       ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-       ioarcb->write_data_transfer_length = cpu_to_be32(xfer_len);
+       ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_WRITE_LAST);
 }
 
 /**
@@ -5742,7 +6469,9 @@ static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd)
                              ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
                              length);
 
-       ipr_cmd->job_step = ipr_setup_write_cache;
+       ipr_cmd->job_step = ipr_set_supported_devs;
+       ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
+                                   struct ipr_resource_entry, queue);
        ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
 
        LEAVE;
@@ -5762,9 +6491,8 @@ static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd)
  **/
 static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd,
                                 __be32 res_handle,
-                                u8 parm, u32 dma_addr, u8 xfer_len)
+                                u8 parm, dma_addr_t dma_addr, u8 xfer_len)
 {
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
 
        ioarcb->res_handle = res_handle;
@@ -5773,11 +6501,7 @@ static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd,
        ioarcb->cmd_pkt.cdb[4] = xfer_len;
        ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
 
-       ioadl->flags_and_data_len =
-               cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len);
-       ioadl->address = cpu_to_be32(dma_addr);
-       ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-       ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len);
+       ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_READ_LAST);
 }
 
 /**
@@ -5815,10 +6539,13 @@ static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd)
  **/
 static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd)
 {
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
 
        if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
-               ipr_cmd->job_step = ipr_setup_write_cache;
+               ipr_cmd->job_step = ipr_set_supported_devs;
+               ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
+                                           struct ipr_resource_entry, queue);
                return IPR_RC_JOB_CONTINUE;
        }
 
@@ -5958,24 +6685,36 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_resource_entry *res, *temp;
-       struct ipr_config_table_entry *cfgte;
-       int found, i;
+       struct ipr_config_table_entry_wrapper cfgtew;
+       int entries, found, flag, i;
        LIST_HEAD(old_res);
 
        ENTER;
-       if (ioa_cfg->cfg_table->hdr.flags & IPR_UCODE_DOWNLOAD_REQ)
+       if (ioa_cfg->sis64)
+               flag = ioa_cfg->u.cfg_table64->hdr64.flags;
+       else
+               flag = ioa_cfg->u.cfg_table->hdr.flags;
+
+       if (flag & IPR_UCODE_DOWNLOAD_REQ)
                dev_err(&ioa_cfg->pdev->dev, "Microcode download required\n");
 
        list_for_each_entry_safe(res, temp, &ioa_cfg->used_res_q, queue)
                list_move_tail(&res->queue, &old_res);
 
-       for (i = 0; i < ioa_cfg->cfg_table->hdr.num_entries; i++) {
-               cfgte = &ioa_cfg->cfg_table->dev[i];
+       if (ioa_cfg->sis64)
+               entries = ioa_cfg->u.cfg_table64->hdr64.num_entries;
+       else
+               entries = ioa_cfg->u.cfg_table->hdr.num_entries;
+
+       for (i = 0; i < entries; i++) {
+               if (ioa_cfg->sis64)
+                       cfgtew.u.cfgte64 = &ioa_cfg->u.cfg_table64->dev[i];
+               else
+                       cfgtew.u.cfgte = &ioa_cfg->u.cfg_table->dev[i];
                found = 0;
 
                list_for_each_entry_safe(res, temp, &old_res, queue) {
-                       if (!memcmp(&res->cfgte.res_addr,
-                                   &cfgte->res_addr, sizeof(cfgte->res_addr))) {
+                       if (ipr_is_same_device(res, &cfgtew)) {
                                list_move_tail(&res->queue, &ioa_cfg->used_res_q);
                                found = 1;
                                break;
@@ -5992,24 +6731,27 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
                        res = list_entry(ioa_cfg->free_res_q.next,
                                         struct ipr_resource_entry, queue);
                        list_move_tail(&res->queue, &ioa_cfg->used_res_q);
-                       ipr_init_res_entry(res);
+                       ipr_init_res_entry(res, &cfgtew);
                        res->add_to_ml = 1;
                }
 
                if (found)
-                       memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));
+                       ipr_update_res_entry(res, &cfgtew);
        }
 
        list_for_each_entry_safe(res, temp, &old_res, queue) {
                if (res->sdev) {
                        res->del_from_ml = 1;
-                       res->cfgte.res_handle = IPR_INVALID_RES_HANDLE;
+                       res->res_handle = IPR_INVALID_RES_HANDLE;
                        list_move_tail(&res->queue, &ioa_cfg->used_res_q);
-               } else {
-                       list_move_tail(&res->queue, &ioa_cfg->free_res_q);
                }
        }
 
+       list_for_each_entry_safe(res, temp, &old_res, queue) {
+               ipr_clear_res_target(res);
+               list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+       }
+
        if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
                ipr_cmd->job_step = ipr_ioafp_mode_sense_page24;
        else
@@ -6033,7 +6775,6 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
        struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
 
@@ -6047,16 +6788,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
        ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
 
        ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG;
-       ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_config_table) >> 8) & 0xff;
-       ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_config_table) & 0xff;
-
-       ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-       ioarcb->read_data_transfer_length =
-               cpu_to_be32(sizeof(struct ipr_config_table));
+       ioarcb->cmd_pkt.cdb[7] = (ioa_cfg->cfg_table_size >> 8) & 0xff;
+       ioarcb->cmd_pkt.cdb[8] = ioa_cfg->cfg_table_size & 0xff;
 
-       ioadl->address = cpu_to_be32(ioa_cfg->cfg_table_dma);
-       ioadl->flags_and_data_len =
-               cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(struct ipr_config_table));
+       ipr_init_ioadl(ipr_cmd, ioa_cfg->cfg_table_dma, ioa_cfg->cfg_table_size,
+                      IPR_IOADL_FLAGS_READ_LAST);
 
        ipr_cmd->job_step = ipr_init_res_table;
 
@@ -6076,10 +6812,9 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
  *     none
  **/
 static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page,
-                             u32 dma_addr, u8 xfer_len)
+                             dma_addr_t dma_addr, u8 xfer_len)
 {
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-       struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
 
        ENTER;
        ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
@@ -6090,12 +6825,7 @@ static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page,
        ioarcb->cmd_pkt.cdb[2] = page;
        ioarcb->cmd_pkt.cdb[4] = xfer_len;
 
-       ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
-       ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len);
-
-       ioadl->address = cpu_to_be32(dma_addr);
-       ioadl->flags_and_data_len =
-               cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len);
+       ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_READ_LAST);
 
        ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
        LEAVE;
@@ -6166,13 +6896,9 @@ static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
 static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-       struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
 
        ENTER;
 
-       if (!ipr_inquiry_page_supported(page0, 1))
-               ioa_cfg->cache_state = CACHE_NONE;
-
        ipr_cmd->job_step = ipr_ioafp_cap_inquiry;
 
        ipr_ioafp_inquiry(ipr_cmd, 1, 3,
@@ -6240,7 +6966,7 @@ static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd)
 }
 
 /**
- * ipr_ioafp_indentify_hrrq - Send Identify Host RRQ.
+ * ipr_ioafp_identify_hrrq - Send Identify Host RRQ.
  * @ipr_cmd:   ipr command struct
  *
  * This function send an Identify Host Request Response Queue
@@ -6249,7 +6975,7 @@ static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     IPR_RC_JOB_RETURN
  **/
-static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd)
+static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
@@ -6261,19 +6987,32 @@ static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd)
        ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
 
        ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+       if (ioa_cfg->sis64)
+               ioarcb->cmd_pkt.cdb[1] = 0x1;
        ioarcb->cmd_pkt.cdb[2] =
-               ((u32) ioa_cfg->host_rrq_dma >> 24) & 0xff;
+               ((u64) ioa_cfg->host_rrq_dma >> 24) & 0xff;
        ioarcb->cmd_pkt.cdb[3] =
-               ((u32) ioa_cfg->host_rrq_dma >> 16) & 0xff;
+               ((u64) ioa_cfg->host_rrq_dma >> 16) & 0xff;
        ioarcb->cmd_pkt.cdb[4] =
-               ((u32) ioa_cfg->host_rrq_dma >> 8) & 0xff;
+               ((u64) ioa_cfg->host_rrq_dma >> 8) & 0xff;
        ioarcb->cmd_pkt.cdb[5] =
-               ((u32) ioa_cfg->host_rrq_dma) & 0xff;
+               ((u64) ioa_cfg->host_rrq_dma) & 0xff;
        ioarcb->cmd_pkt.cdb[7] =
                ((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff;
        ioarcb->cmd_pkt.cdb[8] =
                (sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff;
 
+       if (ioa_cfg->sis64) {
+               ioarcb->cmd_pkt.cdb[10] =
+                       ((u64) ioa_cfg->host_rrq_dma >> 56) & 0xff;
+               ioarcb->cmd_pkt.cdb[11] =
+                       ((u64) ioa_cfg->host_rrq_dma >> 48) & 0xff;
+               ioarcb->cmd_pkt.cdb[12] =
+                       ((u64) ioa_cfg->host_rrq_dma >> 40) & 0xff;
+               ioarcb->cmd_pkt.cdb[13] =
+                       ((u64) ioa_cfg->host_rrq_dma >> 32) & 0xff;
+       }
+
        ipr_cmd->job_step = ipr_ioafp_std_inquiry;
 
        ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
@@ -6354,7 +7093,58 @@ static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg)
        ioa_cfg->toggle_bit = 1;
 
        /* Zero out config table */
-       memset(ioa_cfg->cfg_table, 0, sizeof(struct ipr_config_table));
+       memset(ioa_cfg->u.cfg_table, 0, ioa_cfg->cfg_table_size);
+}
+
+/**
+ * ipr_reset_next_stage - Process IPL stage change based on feedback register.
+ * @ipr_cmd:   ipr command struct
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd)
+{
+       unsigned long stage, stage_time;
+       u32 feedback;
+       volatile u32 int_reg;
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       u64 maskval = 0;
+
+       feedback = readl(ioa_cfg->regs.init_feedback_reg);
+       stage = feedback & IPR_IPL_INIT_STAGE_MASK;
+       stage_time = feedback & IPR_IPL_INIT_STAGE_TIME_MASK;
+
+       ipr_dbg("IPL stage = 0x%lx, IPL stage time = %ld\n", stage, stage_time);
+
+       /* sanity check the stage_time value */
+       if (stage_time < IPR_IPL_INIT_MIN_STAGE_TIME)
+               stage_time = IPR_IPL_INIT_MIN_STAGE_TIME;
+       else if (stage_time > IPR_LONG_OPERATIONAL_TIMEOUT)
+               stage_time = IPR_LONG_OPERATIONAL_TIMEOUT;
+
+       if (stage == IPR_IPL_INIT_STAGE_UNKNOWN) {
+               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.set_interrupt_mask_reg);
+               int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+               stage_time = ioa_cfg->transop_timeout;
+               ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
+       } else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) {
+               ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
+               maskval = IPR_PCII_IPL_STAGE_CHANGE;
+               maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
+               writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
+               int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+               return IPR_RC_JOB_CONTINUE;
+       }
+
+       ipr_cmd->timer.data = (unsigned long) ipr_cmd;
+       ipr_cmd->timer.expires = jiffies + stage_time * HZ;
+       ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
+       ipr_cmd->done = ipr_reset_ioa_job;
+       add_timer(&ipr_cmd->timer);
+       list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+
+       return IPR_RC_JOB_RETURN;
 }
 
 /**
@@ -6373,7 +7163,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
        volatile u32 int_reg;
 
        ENTER;
-       ipr_cmd->job_step = ipr_ioafp_indentify_hrrq;
+       ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
        ipr_init_ioa_mem(ioa_cfg);
 
        ioa_cfg->allow_interrupts = 1;
@@ -6381,19 +7171,27 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
 
        if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
                writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED),
-                      ioa_cfg->regs.clr_interrupt_mask_reg);
+                      ioa_cfg->regs.clr_interrupt_mask_reg32);
                int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
                return IPR_RC_JOB_CONTINUE;
        }
 
        /* Enable destructive diagnostics on IOA */
-       writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg);
+       writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg32);
+
+       writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg32);
+       if (ioa_cfg->sis64)
+               writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_mask_reg);
 
-       writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg);
        int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
 
        dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
 
+       if (ioa_cfg->sis64) {
+               ipr_cmd->job_step = ipr_reset_next_stage;
+               return IPR_RC_JOB_CONTINUE;
+       }
+
        ipr_cmd->timer.data = (unsigned long) ipr_cmd;
        ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
        ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
@@ -6463,7 +7261,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
 
        mailbox = readl(ioa_cfg->ioa_mailbox);
 
-       if (!ipr_sdt_is_fmt2(mailbox)) {
+       if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(mailbox)) {
                ipr_unit_check_no_data(ioa_cfg);
                return;
        }
@@ -6472,15 +7270,20 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
        rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt,
                                        (sizeof(struct ipr_uc_sdt)) / sizeof(__be32));
 
-       if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) ||
-           !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) {
+       if (rc || !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY) ||
+           ((be32_to_cpu(sdt.hdr.state) != IPR_FMT3_SDT_READY_TO_USE) &&
+           (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) {
                ipr_unit_check_no_data(ioa_cfg);
                return;
        }
 
        /* Find length of the first sdt entry (UC buffer) */
-       length = (be32_to_cpu(sdt.entry[0].end_offset) -
-                 be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK;
+       if (be32_to_cpu(sdt.hdr.state) == IPR_FMT3_SDT_READY_TO_USE)
+               length = be32_to_cpu(sdt.entry[0].end_token);
+       else
+               length = (be32_to_cpu(sdt.entry[0].end_token) -
+                         be32_to_cpu(sdt.entry[0].start_token)) &
+                         IPR_FMT2_MBX_ADDR_MASK;
 
        hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
                             struct ipr_hostrcb, queue);
@@ -6488,13 +7291,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
        memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
 
        rc = ipr_get_ldump_data_section(ioa_cfg,
-                                       be32_to_cpu(sdt.entry[0].bar_str_offset),
+                                       be32_to_cpu(sdt.entry[0].start_token),
                                        (__be32 *)&hostrcb->hcam,
                                        min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
 
        if (!rc) {
                ipr_handle_log_data(ioa_cfg, hostrcb);
-               ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+               ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
                if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
                    ioa_cfg->sdt_state == GET_DUMP)
                        ioa_cfg->sdt_state = WAIT_FOR_DUMP;
@@ -6722,7 +7525,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
 
        if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) {
                ipr_mask_and_clear_interrupts(ioa_cfg, ~0);
-               writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
+               writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32);
                ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
        } else {
                ipr_cmd->job_step = ioa_cfg->reset;
@@ -6785,7 +7588,10 @@ static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd)
        ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8;
        ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff;
 
-       ipr_build_ucode_ioadl(ipr_cmd, sglist);
+       if (ioa_cfg->sis64)
+               ipr_build_ucode_ioadl64(ipr_cmd, sglist);
+       else
+               ipr_build_ucode_ioadl(ipr_cmd, sglist);
        ipr_cmd->job_step = ipr_reset_ucode_download_done;
 
        ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
@@ -7154,8 +7960,8 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
        ipr_free_cmd_blks(ioa_cfg);
        pci_free_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS,
                            ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma);
-       pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table),
-                           ioa_cfg->cfg_table,
+       pci_free_consistent(ioa_cfg->pdev, ioa_cfg->cfg_table_size,
+                           ioa_cfg->u.cfg_table,
                            ioa_cfg->cfg_table_dma);
 
        for (i = 0; i < IPR_NUM_HCAMS; i++) {
@@ -7209,7 +8015,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
        int i;
 
        ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev,
-                                                sizeof(struct ipr_cmnd), 8, 0);
+                                                sizeof(struct ipr_cmnd), 16, 0);
 
        if (!ioa_cfg->ipr_cmd_pool)
                return -ENOMEM;
@@ -7227,13 +8033,25 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
                ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr;
 
                ioarcb = &ipr_cmd->ioarcb;
-               ioarcb->ioarcb_host_pci_addr = cpu_to_be32(dma_addr);
+               ipr_cmd->dma_addr = dma_addr;
+               if (ioa_cfg->sis64)
+                       ioarcb->a.ioarcb_host_pci_addr64 = cpu_to_be64(dma_addr);
+               else
+                       ioarcb->a.ioarcb_host_pci_addr = cpu_to_be32(dma_addr);
+
                ioarcb->host_response_handle = cpu_to_be32(i << 2);
-               ioarcb->write_ioadl_addr =
-                       cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
-               ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
-               ioarcb->ioasa_host_pci_addr =
-                       cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+               if (ioa_cfg->sis64) {
+                       ioarcb->u.sis64_addr_data.data_ioadl_addr =
+                               cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
+                       ioarcb->u.sis64_addr_data.ioasa_host_pci_addr =
+                               cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+               } else {
+                       ioarcb->write_ioadl_addr =
+                               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
+                       ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+                       ioarcb->ioasa_host_pci_addr =
+                               cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+               }
                ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa));
                ipr_cmd->cmd_index = i;
                ipr_cmd->ioa_cfg = ioa_cfg;
@@ -7260,13 +8078,24 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
 
        ENTER;
        ioa_cfg->res_entries = kzalloc(sizeof(struct ipr_resource_entry) *
-                                      IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL);
+                                      ioa_cfg->max_devs_supported, GFP_KERNEL);
 
        if (!ioa_cfg->res_entries)
                goto out;
 
-       for (i = 0; i < IPR_MAX_PHYSICAL_DEVS; i++)
+       if (ioa_cfg->sis64) {
+               ioa_cfg->target_ids = kzalloc(sizeof(unsigned long) *
+                                             BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
+               ioa_cfg->array_ids = kzalloc(sizeof(unsigned long) *
+                                            BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
+               ioa_cfg->vset_ids = kzalloc(sizeof(unsigned long) *
+                                           BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
+       }
+
+       for (i = 0; i < ioa_cfg->max_devs_supported; i++) {
                list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q);
+               ioa_cfg->res_entries[i].ioa_cfg = ioa_cfg;
+       }
 
        ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev,
                                                sizeof(struct ipr_misc_cbs),
@@ -7285,11 +8114,11 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
        if (!ioa_cfg->host_rrq)
                goto out_ipr_free_cmd_blocks;
 
-       ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev,
-                                                 sizeof(struct ipr_config_table),
-                                                 &ioa_cfg->cfg_table_dma);
+       ioa_cfg->u.cfg_table = pci_alloc_consistent(ioa_cfg->pdev,
+                                                   ioa_cfg->cfg_table_size,
+                                                   &ioa_cfg->cfg_table_dma);
 
-       if (!ioa_cfg->cfg_table)
+       if (!ioa_cfg->u.cfg_table)
                goto out_free_host_rrq;
 
        for (i = 0; i < IPR_NUM_HCAMS; i++) {
@@ -7323,8 +8152,9 @@ out_free_hostrcb_dma:
                                    ioa_cfg->hostrcb[i],
                                    ioa_cfg->hostrcb_dma[i]);
        }
-       pci_free_consistent(pdev, sizeof(struct ipr_config_table),
-                           ioa_cfg->cfg_table, ioa_cfg->cfg_table_dma);
+       pci_free_consistent(pdev, ioa_cfg->cfg_table_size,
+                           ioa_cfg->u.cfg_table,
+                           ioa_cfg->cfg_table_dma);
 out_free_host_rrq:
        pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS,
                            ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma);
@@ -7399,15 +8229,21 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
        init_waitqueue_head(&ioa_cfg->reset_wait_q);
        init_waitqueue_head(&ioa_cfg->msi_wait_q);
        ioa_cfg->sdt_state = INACTIVE;
-       if (ipr_enable_cache)
-               ioa_cfg->cache_state = CACHE_ENABLED;
-       else
-               ioa_cfg->cache_state = CACHE_DISABLED;
 
        ipr_initialize_bus_attr(ioa_cfg);
+       ioa_cfg->max_devs_supported = ipr_max_devs;
 
-       host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
-       host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
+       if (ioa_cfg->sis64) {
+               host->max_id = IPR_MAX_SIS64_TARGETS_PER_BUS;
+               host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
+               if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
+                       ioa_cfg->max_devs_supported = IPR_MAX_SIS64_DEVS;
+       } else {
+               host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
+               host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
+               if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
+                       ioa_cfg->max_devs_supported = IPR_MAX_PHYSICAL_DEVS;
+       }
        host->max_channel = IPR_MAX_BUS_TO_SCAN;
        host->unique_id = host->host_no;
        host->max_cmd_len = IPR_MAX_CDB_LEN;
@@ -7419,13 +8255,26 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
 
        t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
        t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+       t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
        t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+       t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
        t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+       t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
        t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+       t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
        t->ioarrin_reg = base + p->ioarrin_reg;
        t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+       t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
        t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+       t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
        t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
+       t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
+
+       if (ioa_cfg->sis64) {
+               t->init_feedback_reg = base + p->init_feedback_reg;
+               t->dump_addr_reg = base + p->dump_addr_reg;
+               t->dump_data_reg = base + p->dump_data_reg;
+       }
 }
 
 /**
@@ -7497,7 +8346,7 @@ static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
        init_waitqueue_head(&ioa_cfg->msi_wait_q);
        ioa_cfg->msi_received = 0;
        ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
-       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg);
+       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg32);
        int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 
@@ -7508,7 +8357,7 @@ static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
        } else if (ipr_debug)
                dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq);
 
-       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg);
+       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg32);
        int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
        wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ);
        ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
@@ -7578,6 +8427,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto out_scsi_host_put;
        }
 
+       /* set SIS 32 or SIS 64 */
+       ioa_cfg->sis64 = ioa_cfg->ipr_chip->sis_type == IPR_SIS64 ? 1 : 0;
        ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg;
 
        if (ipr_transop_timeout)
@@ -7615,7 +8466,16 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (ioa_cfg->sis64) {
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (rc < 0) {
+                       dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n");
+                       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               }
+
+       } else
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+
        if (rc < 0) {
                dev_err(&pdev->dev, "Failed to set PCI DMA mask\n");
                goto cleanup_nomem;
@@ -7657,6 +8517,15 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
                goto cleanup_nomem;
 
+       if (ioa_cfg->sis64)
+               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
+                               + ((sizeof(struct ipr_config_table_entry64)
+                               * ioa_cfg->max_devs_supported)));
+       else
+               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
+                               + ((sizeof(struct ipr_config_table_entry)
+                               * ioa_cfg->max_devs_supported)));
+
        rc = ipr_alloc_mem(ioa_cfg);
        if (rc < 0) {
                dev_err(&pdev->dev,
@@ -7668,9 +8537,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
         * If HRRQ updated interrupt is not masked, or reset alert is set,
         * the card is in an unknown state and needs a hard reset
         */
-       mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
-       interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
-       uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
+       mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
+       interrupts = readl(ioa_cfg->regs.sense_interrupt_reg32);
+       uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg32);
        if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
                ioa_cfg->needs_hard_reset = 1;
        if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
@@ -7958,9 +8827,6 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
-             IPR_USE_LONG_TRANSOP_TIMEOUT },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
@@ -7975,9 +8841,22 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0,
                IPR_USE_LONG_TRANSOP_TIMEOUT },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E,
-               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0,
-               IPR_USE_LONG_TRANSOP_TIMEOUT },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B5, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B2, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B1, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C6, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CE, 0, 0, 0 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
@@ -7997,6 +8876,61 @@ static struct pci_driver ipr_driver = {
 };
 
 /**
+ * ipr_halt_done - Shutdown prepare completion
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_halt_done(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+       list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+}
+
+/**
+ * ipr_halt - Issue shutdown prepare to all adapters
+ *
+ * Return value:
+ *     NOTIFY_OK on success / NOTIFY_DONE on failure
+ **/
+static int ipr_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+       struct ipr_cmnd *ipr_cmd;
+       struct ipr_ioa_cfg *ioa_cfg;
+       unsigned long flags = 0;
+
+       if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
+               return NOTIFY_DONE;
+
+       spin_lock(&ipr_driver_lock);
+
+       list_for_each_entry(ioa_cfg, &ipr_ioa_head, queue) {
+               spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+               if (!ioa_cfg->allow_cmds) {
+                       spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+                       continue;
+               }
+
+               ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+               ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+               ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+               ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
+               ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_SHUTDOWN_PREPARE_FOR_NORMAL;
+
+               ipr_do_req(ipr_cmd, ipr_halt_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+       }
+       spin_unlock(&ipr_driver_lock);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block ipr_notifier = {
+       ipr_halt, NULL, 0
+};
+
+/**
  * ipr_init - Module entry point
  *
  * Return value:
@@ -8007,6 +8941,7 @@ static int __init ipr_init(void)
        ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
                 IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
 
+       register_reboot_notifier(&ipr_notifier);
        return pci_register_driver(&ipr_driver);
 }
 
@@ -8020,6 +8955,7 @@ static int __init ipr_init(void)
  **/
 static void __exit ipr_exit(void)
 {
+       unregister_reboot_notifier(&ipr_notifier);
        pci_unregister_driver(&ipr_driver);
 }
 
index 19bbcf3..4c267b5 100644 (file)
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.4.3"
-#define IPR_DRIVER_DATE "(June 10, 2009)"
+#define IPR_DRIVER_VERSION "2.5.0"
+#define IPR_DRIVER_DATE "(February 11, 2010)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -55,7 +55,9 @@
 #define IPR_NUM_BASE_CMD_BLKS                          100
 
 #define PCI_DEVICE_ID_IBM_OBSIDIAN_E   0x0339
-#define PCI_DEVICE_ID_IBM_SCAMP_E              0x034A
+
+#define PCI_DEVICE_ID_IBM_CROC_FPGA_E2          0x033D
+#define PCI_DEVICE_ID_IBM_CROC_ASIC_E2          0x034A
 
 #define IPR_SUBS_DEV_ID_2780   0x0264
 #define IPR_SUBS_DEV_ID_5702   0x0266
 #define IPR_SUBS_DEV_ID_572A   0x02C1
 #define IPR_SUBS_DEV_ID_572B   0x02C2
 #define IPR_SUBS_DEV_ID_572F   0x02C3
-#define IPR_SUBS_DEV_ID_574D   0x030B
 #define IPR_SUBS_DEV_ID_574E   0x030A
 #define IPR_SUBS_DEV_ID_575B   0x030D
 #define IPR_SUBS_DEV_ID_575C   0x0338
-#define IPR_SUBS_DEV_ID_575D   0x033E
 #define IPR_SUBS_DEV_ID_57B3   0x033A
 #define IPR_SUBS_DEV_ID_57B7   0x0360
 #define IPR_SUBS_DEV_ID_57B8   0x02C2
 
+#define IPR_SUBS_DEV_ID_57B4    0x033B
+#define IPR_SUBS_DEV_ID_57B2    0x035F
+#define IPR_SUBS_DEV_ID_57C6    0x0357
+
+#define IPR_SUBS_DEV_ID_57B5    0x033C
+#define IPR_SUBS_DEV_ID_57CE    0x035E
+#define IPR_SUBS_DEV_ID_57B1    0x0355
+
+#define IPR_SUBS_DEV_ID_574D    0x0356
+#define IPR_SUBS_DEV_ID_575D    0x035D
+
 #define IPR_NAME                               "ipr"
 
 /*
 #define IPR_NUM_LOG_HCAMS                              2
 #define IPR_NUM_CFG_CHG_HCAMS                          2
 #define IPR_NUM_HCAMS  (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
+
+#define IPR_MAX_SIS64_TARGETS_PER_BUS                  1024
+#define IPR_MAX_SIS64_LUNS_PER_TARGET                  0xffffffff
+
 #define IPR_MAX_NUM_TARGETS_PER_BUS                    256
 #define IPR_MAX_NUM_LUNS_PER_TARGET                    256
 #define IPR_MAX_NUM_VSET_LUNS_PER_TARGET       8
 
 /* We need resources for HCAMS, IOA reset, IOA bringdown, and ERP */
 #define IPR_NUM_INTERNAL_CMD_BLKS      (IPR_NUM_HCAMS + \
-                                     ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 3)
+                                     ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 4)
 
 #define IPR_MAX_COMMANDS               IPR_NUM_BASE_CMD_BLKS
 #define IPR_NUM_CMD_BLKS               (IPR_NUM_BASE_CMD_BLKS + \
                                                IPR_NUM_INTERNAL_CMD_BLKS)
 
 #define IPR_MAX_PHYSICAL_DEVS                          192
+#define IPR_DEFAULT_SIS64_DEVS                         1024
+#define IPR_MAX_SIS64_DEVS                             4096
 
 #define IPR_MAX_SGLIST                                 64
 #define IPR_IOA_MAX_SECTORS                            32767
 #define        IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE      0x01
 #define        IPR_HCAM_CDB_OP_CODE_LOG_DATA           0x02
 #define IPR_SET_SUPPORTED_DEVICES                      0xFB
+#define IPR_SET_ALL_SUPPORTED_DEVICES                  0x80
 #define IPR_IOA_SHUTDOWN                               0xF7
 #define        IPR_WR_BUF_DOWNLOAD_AND_SAVE                    0x05
 
 #define IPR_SDT_FMT2_BAR5_SEL                          0x5
 #define IPR_SDT_FMT2_EXP_ROM_SEL                       0x8
 #define IPR_FMT2_SDT_READY_TO_USE                      0xC4D4E3F2
+#define IPR_FMT3_SDT_READY_TO_USE                      0xC4D4E3F3
 #define IPR_DOORBELL                                   0x82800000
 #define IPR_RUNTIME_RESET                              0x40000000
 
+#define IPR_IPL_INIT_MIN_STAGE_TIME                    5
+#define IPR_IPL_INIT_STAGE_UNKNOWN                     0x0
+#define IPR_IPL_INIT_STAGE_TRANSOP                     0xB0000000
+#define IPR_IPL_INIT_STAGE_MASK                                0xff000000
+#define IPR_IPL_INIT_STAGE_TIME_MASK                   0x0000ffff
+#define IPR_PCII_IPL_STAGE_CHANGE                      (0x80000000 >> 0)
+
 #define IPR_PCII_IOA_TRANS_TO_OPER                     (0x80000000 >> 0)
 #define IPR_PCII_IOARCB_XFER_FAILED                    (0x80000000 >> 3)
 #define IPR_PCII_IOA_UNIT_CHECKED                      (0x80000000 >> 4)
@@ -318,27 +344,27 @@ struct ipr_std_inq_data {
        u8 serial_num[IPR_SERIAL_NUM_LEN];
 }__attribute__ ((packed));
 
+#define IPR_RES_TYPE_AF_DASD           0x00
+#define IPR_RES_TYPE_GENERIC_SCSI      0x01
+#define IPR_RES_TYPE_VOLUME_SET                0x02
+#define IPR_RES_TYPE_REMOTE_AF_DASD    0x03
+#define IPR_RES_TYPE_GENERIC_ATA       0x04
+#define IPR_RES_TYPE_ARRAY             0x05
+#define IPR_RES_TYPE_IOAFP             0xff
+
 struct ipr_config_table_entry {
        u8 proto;
 #define IPR_PROTO_SATA                 0x02
 #define IPR_PROTO_SATA_ATAPI           0x03
 #define IPR_PROTO_SAS_STP              0x06
-#define IPR_PROTO_SAS_STP_ATAPI        0x07
+#define IPR_PROTO_SAS_STP_ATAPI                0x07
        u8 array_id;
        u8 flags;
-#define IPR_IS_IOA_RESOURCE    0x80
-#define IPR_IS_ARRAY_MEMBER 0x20
-#define IPR_IS_HOT_SPARE       0x10
-
+#define IPR_IS_IOA_RESOURCE            0x80
        u8 rsvd_subtype;
-#define IPR_RES_SUBTYPE(res) (((res)->cfgte.rsvd_subtype) & 0x0f)
-#define IPR_SUBTYPE_AF_DASD                    0
-#define IPR_SUBTYPE_GENERIC_SCSI       1
-#define IPR_SUBTYPE_VOLUME_SET         2
-#define IPR_SUBTYPE_GENERIC_ATA        4
-
-#define IPR_QUEUEING_MODEL(res)        ((((res)->cfgte.flags) & 0x70) >> 4)
-#define IPR_QUEUE_FROZEN_MODEL 0
+
+#define IPR_QUEUEING_MODEL(res)        ((((res)->flags) & 0x70) >> 4)
+#define IPR_QUEUE_FROZEN_MODEL         0
 #define IPR_QUEUE_NACA_MODEL           1
 
        struct ipr_res_addr res_addr;
@@ -347,6 +373,28 @@ struct ipr_config_table_entry {
        struct ipr_std_inq_data std_inq_data;
 }__attribute__ ((packed, aligned (4)));
 
+struct ipr_config_table_entry64 {
+       u8 res_type;
+       u8 proto;
+       u8 vset_num;
+       u8 array_id;
+       __be16 flags;
+       __be16 res_flags;
+#define IPR_QUEUEING_MODEL64(res) ((((res)->res_flags) & 0x7000) >> 12)
+       __be32 res_handle;
+       u8 dev_id_type;
+       u8 reserved[3];
+       __be64 dev_id;
+       __be64 lun;
+       __be64 lun_wwn[2];
+#define IPR_MAX_RES_PATH_LENGTH                24
+       __be64 res_path;
+       struct ipr_std_inq_data std_inq_data;
+       u8 reserved2[4];
+       __be64 reserved3[2]; // description text
+       u8 reserved4[8];
+}__attribute__ ((packed, aligned (8)));
+
 struct ipr_config_table_hdr {
        u8 num_entries;
        u8 flags;
@@ -354,13 +402,35 @@ struct ipr_config_table_hdr {
        __be16 reserved;
 }__attribute__((packed, aligned (4)));
 
+struct ipr_config_table_hdr64 {
+       __be16 num_entries;
+       __be16 reserved;
+       u8 flags;
+       u8 reserved2[11];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_config_table {
        struct ipr_config_table_hdr hdr;
-       struct ipr_config_table_entry dev[IPR_MAX_PHYSICAL_DEVS];
+       struct ipr_config_table_entry dev[0];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_config_table64 {
+       struct ipr_config_table_hdr64 hdr64;
+       struct ipr_config_table_entry64 dev[0];
+}__attribute__((packed, aligned (8)));
+
+struct ipr_config_table_entry_wrapper {
+       union {
+               struct ipr_config_table_entry *cfgte;
+               struct ipr_config_table_entry64 *cfgte64;
+       } u;
+};
+
 struct ipr_hostrcb_cfg_ch_not {
-       struct ipr_config_table_entry cfgte;
+       union {
+               struct ipr_config_table_entry cfgte;
+               struct ipr_config_table_entry64 cfgte64;
+       } u;
        u8 reserved[936];
 }__attribute__((packed, aligned (4)));
 
@@ -381,7 +451,7 @@ struct ipr_cmd_pkt {
 #define IPR_RQTYPE_HCAM                        0x02
 #define IPR_RQTYPE_ATA_PASSTHRU        0x04
 
-       u8 luntar_luntrn;
+       u8 reserved2;
 
        u8 flags_hi;
 #define IPR_FLAGS_HI_WRITE_NOT_READ            0x80
@@ -403,7 +473,7 @@ struct ipr_cmd_pkt {
        __be16 timeout;
 }__attribute__ ((packed, aligned(4)));
 
-struct ipr_ioarcb_ata_regs {
+struct ipr_ioarcb_ata_regs {   /* 22 bytes */
        u8 flags;
 #define IPR_ATA_FLAG_PACKET_CMD                        0x80
 #define IPR_ATA_FLAG_XFER_TYPE_DMA                     0x40
@@ -442,28 +512,49 @@ struct ipr_ioadl_desc {
        __be32 address;
 }__attribute__((packed, aligned (8)));
 
+struct ipr_ioadl64_desc {
+       __be32 flags;
+       __be32 data_len;
+       __be64 address;
+}__attribute__((packed, aligned (16)));
+
+struct ipr_ata64_ioadl {
+       struct ipr_ioarcb_ata_regs regs;
+       u16 reserved[5];
+       struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES];
+}__attribute__((packed, aligned (16)));
+
 struct ipr_ioarcb_add_data {
        union {
                struct ipr_ioarcb_ata_regs regs;
                struct ipr_ioadl_desc ioadl[5];
                __be32 add_cmd_parms[10];
-       }u;
-}__attribute__ ((packed, aligned(4)));
+       } u;
+}__attribute__ ((packed, aligned (4)));
+
+struct ipr_ioarcb_sis64_add_addr_ecb {
+       __be64 ioasa_host_pci_addr;
+       __be64 data_ioadl_addr;
+       __be64 reserved;
+       __be32 ext_control_buf[4];
+}__attribute__((packed, aligned (8)));
 
 /* IOA Request Control Block    128 bytes  */
 struct ipr_ioarcb {
-       __be32 ioarcb_host_pci_addr;
-       __be32 reserved;
+       union {
+               __be32 ioarcb_host_pci_addr;
+               __be64 ioarcb_host_pci_addr64;
+       } a;
        __be32 res_handle;
        __be32 host_response_handle;
        __be32 reserved1;
        __be32 reserved2;
        __be32 reserved3;
 
-       __be32 write_data_transfer_length;
+       __be32 data_transfer_length;
        __be32 read_data_transfer_length;
        __be32 write_ioadl_addr;
-       __be32 write_ioadl_len;
+       __be32 ioadl_len;
        __be32 read_ioadl_addr;
        __be32 read_ioadl_len;
 
@@ -473,8 +564,14 @@ struct ipr_ioarcb {
 
        struct ipr_cmd_pkt cmd_pkt;
 
-       __be32 add_cmd_parms_len;
-       struct ipr_ioarcb_add_data add_data;
+       __be16 add_cmd_parms_offset;
+       __be16 add_cmd_parms_len;
+
+       union {
+               struct ipr_ioarcb_add_data add_data;
+               struct ipr_ioarcb_sis64_add_addr_ecb sis64_addr_data;
+       } u;
+
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_vset {
@@ -676,12 +773,29 @@ struct ipr_hostrcb_device_data_entry_enhanced {
        struct ipr_ext_vpd cfc_last_with_dev_vpd;
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb64_device_data_entry_enhanced {
+       struct ipr_ext_vpd vpd;
+       u8 ccin[4];
+       u8 res_path[8];
+       struct ipr_ext_vpd new_vpd;
+       u8 new_ccin[4];
+       struct ipr_ext_vpd ioa_last_with_dev_vpd;
+       struct ipr_ext_vpd cfc_last_with_dev_vpd;
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_array_data_entry {
        struct ipr_vpd vpd;
        struct ipr_res_addr expected_dev_res_addr;
        struct ipr_res_addr dev_res_addr;
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb64_array_data_entry {
+       struct ipr_ext_vpd vpd;
+       u8 ccin[4];
+       u8 expected_res_path[8];
+       u8 res_path[8];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_array_data_entry_enhanced {
        struct ipr_ext_vpd vpd;
        u8 ccin[4];
@@ -733,6 +847,14 @@ struct ipr_hostrcb_type_13_error {
        struct ipr_hostrcb_device_data_entry_enhanced dev[3];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb_type_23_error {
+       struct ipr_ext_vpd ioa_vpd;
+       struct ipr_ext_vpd cfc_vpd;
+       __be32 errors_detected;
+       __be32 errors_logged;
+       struct ipr_hostrcb64_device_data_entry_enhanced dev[3];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_type_04_error {
        struct ipr_vpd ioa_vpd;
        struct ipr_vpd cfc_vpd;
@@ -760,6 +882,22 @@ struct ipr_hostrcb_type_14_error {
        struct ipr_hostrcb_array_data_entry_enhanced array_member[18];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb_type_24_error {
+       struct ipr_ext_vpd ioa_vpd;
+       struct ipr_ext_vpd cfc_vpd;
+       u8 reserved[2];
+       u8 exposed_mode_adn;
+#define IPR_INVALID_ARRAY_DEV_NUM              0xff
+       u8 array_id;
+       u8 last_res_path[8];
+       u8 protection_level[8];
+       struct ipr_ext_vpd array_vpd;
+       u8 description[16];
+       u8 reserved2[3];
+       u8 num_entries;
+       struct ipr_hostrcb64_array_data_entry array_member[32];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_type_07_error {
        u8 failure_reason[64];
        struct ipr_vpd vpd;
@@ -797,6 +935,22 @@ struct ipr_hostrcb_config_element {
        __be32 wwid[2];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb64_config_element {
+       __be16 length;
+       u8 descriptor_id;
+#define IPR_DESCRIPTOR_MASK            0xC0
+#define IPR_DESCRIPTOR_SIS64           0x00
+
+       u8 reserved;
+       u8 type_status;
+
+       u8 reserved2[2];
+       u8 link_rate;
+
+       u8 res_path[8];
+       __be32 wwid[2];
+}__attribute__((packed, aligned (8)));
+
 struct ipr_hostrcb_fabric_desc {
        __be16 length;
        u8 ioa_port;
@@ -818,6 +972,20 @@ struct ipr_hostrcb_fabric_desc {
        struct ipr_hostrcb_config_element elem[1];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb64_fabric_desc {
+       __be16 length;
+       u8 descriptor_id;
+
+       u8 reserved;
+       u8 path_state;
+
+       u8 reserved2[2];
+       u8 res_path[8];
+       u8 reserved3[6];
+       __be16 num_entries;
+       struct ipr_hostrcb64_config_element elem[1];
+}__attribute__((packed, aligned (8)));
+
 #define for_each_fabric_cfg(fabric, cfg) \
                for (cfg = (fabric)->elem; \
                        cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \
@@ -830,10 +998,17 @@ struct ipr_hostrcb_type_20_error {
        struct ipr_hostrcb_fabric_desc desc[1];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb_type_30_error {
+       u8 failure_reason[64];
+       u8 reserved[3];
+       u8 num_entries;
+       struct ipr_hostrcb64_fabric_desc desc[1];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_error {
-       __be32 failing_dev_ioasc;
-       struct ipr_res_addr failing_dev_res_addr;
-       __be32 failing_dev_res_handle;
+       __be32 fd_ioasc;
+       struct ipr_res_addr fd_res_addr;
+       __be32 fd_res_handle;
        __be32 prc;
        union {
                struct ipr_hostrcb_type_ff_error type_ff_error;
@@ -850,6 +1025,26 @@ struct ipr_hostrcb_error {
        } u;
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb64_error {
+       __be32 fd_ioasc;
+       __be32 ioa_fw_level;
+       __be32 fd_res_handle;
+       __be32 prc;
+       __be64 fd_dev_id;
+       __be64 fd_lun;
+       u8 fd_res_path[8];
+       __be64 time_stamp;
+       u8 reserved[2];
+       union {
+               struct ipr_hostrcb_type_ff_error type_ff_error;
+               struct ipr_hostrcb_type_12_error type_12_error;
+               struct ipr_hostrcb_type_17_error type_17_error;
+               struct ipr_hostrcb_type_23_error type_23_error;
+               struct ipr_hostrcb_type_24_error type_24_error;
+               struct ipr_hostrcb_type_30_error type_30_error;
+       } u;
+}__attribute__((packed, aligned (8)));
+
 struct ipr_hostrcb_raw {
        __be32 data[sizeof(struct ipr_hostrcb_error)/sizeof(__be32)];
 }__attribute__((packed, aligned (4)));
@@ -887,7 +1082,11 @@ struct ipr_hcam {
 #define IPR_HOST_RCB_OVERLAY_ID_16                             0x16
 #define IPR_HOST_RCB_OVERLAY_ID_17                             0x17
 #define IPR_HOST_RCB_OVERLAY_ID_20                             0x20
-#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT                        0xFF
+#define IPR_HOST_RCB_OVERLAY_ID_23                             0x23
+#define IPR_HOST_RCB_OVERLAY_ID_24                             0x24
+#define IPR_HOST_RCB_OVERLAY_ID_26                             0x26
+#define IPR_HOST_RCB_OVERLAY_ID_30                             0x30
+#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT                                0xFF
 
        u8 reserved1[3];
        __be32 ilid;
@@ -897,6 +1096,7 @@ struct ipr_hcam {
 
        union {
                struct ipr_hostrcb_error error;
+               struct ipr_hostrcb64_error error64;
                struct ipr_hostrcb_cfg_ch_not ccn;
                struct ipr_hostrcb_raw raw;
        } u;
@@ -907,14 +1107,14 @@ struct ipr_hostrcb {
        dma_addr_t hostrcb_dma;
        struct list_head queue;
        struct ipr_ioa_cfg *ioa_cfg;
+       char rp_buffer[IPR_MAX_RES_PATH_LENGTH];
 };
 
 /* IPR smart dump table structures */
 struct ipr_sdt_entry {
-       __be32 bar_str_offset;
-       __be32 end_offset;
-       u8 entry_byte;
-       u8 reserved[3];
+       __be32 start_token;
+       __be32 end_token;
+       u8 reserved[4];
 
        u8 flags;
 #define IPR_SDT_ENDIAN         0x80
@@ -960,28 +1160,48 @@ struct ipr_sata_port {
 };
 
 struct ipr_resource_entry {
-       struct ipr_config_table_entry cfgte;
        u8 needs_sync_complete:1;
        u8 in_erp:1;
        u8 add_to_ml:1;
        u8 del_from_ml:1;
        u8 resetting_device:1;
 
+       u32 bus;                /* AKA channel */
+       u32 target;             /* AKA id */
+       u32 lun;
+#define IPR_ARRAY_VIRTUAL_BUS                  0x1
+#define IPR_VSET_VIRTUAL_BUS                   0x2
+#define IPR_IOAFP_VIRTUAL_BUS                  0x3
+
+#define IPR_GET_RES_PHYS_LOC(res) \
+       (((res)->bus << 24) | ((res)->target << 8) | (res)->lun)
+
+       u8 ata_class;
+
+       u8 flags;
+       __be16 res_flags;
+
+       __be32 type;
+
+       u8 qmodel;
+       struct ipr_std_inq_data std_inq_data;
+
+       __be32 res_handle;
+       __be64 dev_id;
+       struct scsi_lun dev_lun;
+       u8 res_path[8];
+
+       struct ipr_ioa_cfg *ioa_cfg;
        struct scsi_device *sdev;
        struct ipr_sata_port *sata_port;
        struct list_head queue;
-};
+}; /* struct ipr_resource_entry */
 
 struct ipr_resource_hdr {
        u16 num_entries;
        u16 reserved;
 };
 
-struct ipr_resource_table {
-       struct ipr_resource_hdr hdr;
-       struct ipr_resource_entry dev[IPR_MAX_PHYSICAL_DEVS];
-};
-
 struct ipr_misc_cbs {
        struct ipr_ioa_vpd ioa_vpd;
        struct ipr_inquiry_page0 page0_data;
@@ -994,27 +1214,51 @@ struct ipr_misc_cbs {
 struct ipr_interrupt_offsets {
        unsigned long set_interrupt_mask_reg;
        unsigned long clr_interrupt_mask_reg;
+       unsigned long clr_interrupt_mask_reg32;
        unsigned long sense_interrupt_mask_reg;
+       unsigned long sense_interrupt_mask_reg32;
        unsigned long clr_interrupt_reg;
+       unsigned long clr_interrupt_reg32;
 
        unsigned long sense_interrupt_reg;
+       unsigned long sense_interrupt_reg32;
        unsigned long ioarrin_reg;
        unsigned long sense_uproc_interrupt_reg;
+       unsigned long sense_uproc_interrupt_reg32;
        unsigned long set_uproc_interrupt_reg;
+       unsigned long set_uproc_interrupt_reg32;
        unsigned long clr_uproc_interrupt_reg;
+       unsigned long clr_uproc_interrupt_reg32;
+
+       unsigned long init_feedback_reg;
+
+       unsigned long dump_addr_reg;
+       unsigned long dump_data_reg;
 };
 
 struct ipr_interrupts {
        void __iomem *set_interrupt_mask_reg;
        void __iomem *clr_interrupt_mask_reg;
+       void __iomem *clr_interrupt_mask_reg32;
        void __iomem *sense_interrupt_mask_reg;
+       void __iomem *sense_interrupt_mask_reg32;
        void __iomem *clr_interrupt_reg;
+       void __iomem *clr_interrupt_reg32;
 
        void __iomem *sense_interrupt_reg;
+       void __iomem *sense_interrupt_reg32;
        void __iomem *ioarrin_reg;
        void __iomem *sense_uproc_interrupt_reg;
+       void __iomem *sense_uproc_interrupt_reg32;
        void __iomem *set_uproc_interrupt_reg;
+       void __iomem *set_uproc_interrupt_reg32;
        void __iomem *clr_uproc_interrupt_reg;
+       void __iomem *clr_uproc_interrupt_reg32;
+
+       void __iomem *init_feedback_reg;
+
+       void __iomem *dump_addr_reg;
+       void __iomem *dump_data_reg;
 };
 
 struct ipr_chip_cfg_t {
@@ -1029,6 +1273,9 @@ struct ipr_chip_t {
        u16 intr_type;
 #define IPR_USE_LSI                    0x00
 #define IPR_USE_MSI                    0x01
+       u16 sis_type;
+#define IPR_SIS32                      0x00
+#define IPR_SIS64                      0x01
        const struct ipr_chip_cfg_t *cfg;
 };
 
@@ -1073,13 +1320,6 @@ enum ipr_sdt_state {
        DUMP_OBTAINED
 };
 
-enum ipr_cache_state {
-       CACHE_NONE,
-       CACHE_DISABLED,
-       CACHE_ENABLED,
-       CACHE_INVALID
-};
-
 /* Per-controller data */
 struct ipr_ioa_cfg {
        char eye_catcher[8];
@@ -1099,10 +1339,17 @@ struct ipr_ioa_cfg {
        u8 dual_raid:1;
        u8 needs_warm_reset:1;
        u8 msi_received:1;
+       u8 sis64:1;
 
        u8 revid;
 
-       enum ipr_cache_state cache_state;
+       /*
+        * Bitmaps for SIS64 generated target values
+        */
+       unsigned long *target_ids;
+       unsigned long *array_ids;
+       unsigned long *vset_ids;
+
        u16 type; /* CCIN of the card */
 
        u8 log_level;
@@ -1133,8 +1380,13 @@ struct ipr_ioa_cfg {
 
        char cfg_table_start[8];
 #define IPR_CFG_TBL_START              "cfg"
-       struct ipr_config_table *cfg_table;
+       union {
+               struct ipr_config_table *cfg_table;
+               struct ipr_config_table64 *cfg_table64;
+       } u;
        dma_addr_t cfg_table_dma;
+       u32 cfg_table_size;
+       u32 max_devs_supported;
 
        char resource_table_label[8];
 #define IPR_RES_TABLE_LABEL            "res_tbl"
@@ -1202,13 +1454,17 @@ struct ipr_ioa_cfg {
        char ipr_cmd_label[8];
 #define IPR_CMD_LABEL          "ipr_cmd"
        struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
-       u32 ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS];
-};
+       dma_addr_t ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS];
+}; /* struct ipr_ioa_cfg */
 
 struct ipr_cmnd {
        struct ipr_ioarcb ioarcb;
+       union {
+               struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
+               struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES];
+               struct ipr_ata64_ioadl ata_ioadl;
+       } i;
        struct ipr_ioasa ioasa;
-       struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
        struct list_head queue;
        struct scsi_cmnd *scsi_cmd;
        struct ata_queued_cmd *qc;
@@ -1221,7 +1477,7 @@ struct ipr_cmnd {
        u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
        dma_addr_t sense_buffer_dma;
        unsigned short dma_use_sg;
-       dma_addr_t dma_handle;
+       dma_addr_t dma_addr;
        struct ipr_cmnd *sibling;
        union {
                enum ipr_shutdown_type shutdown_type;
@@ -1314,8 +1570,6 @@ struct ipr_ioa_dump {
        u32 next_page_index;
        u32 page_offset;
        u32 format;
-#define IPR_SDT_FMT2           2
-#define IPR_SDT_UNKNOWN                3
 }__attribute__((packed, aligned (4)));
 
 struct ipr_dump {
@@ -1377,6 +1631,13 @@ struct ipr_ucode_image_header {
 #define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)
 #define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__))
 
+#define ipr_res_printk(level, ioa_cfg, bus, target, lun, fmt, ...) \
+       printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \
+               bus, target, lun, ##__VA_ARGS__)
+
+#define ipr_res_err(ioa_cfg, res, fmt, ...) \
+       ipr_res_printk(KERN_ERR, ioa_cfg, (res)->bus, (res)->target, (res)->lun, fmt, ##__VA_ARGS__)
+
 #define ipr_ra_printk(level, ioa_cfg, ra, fmt, ...) \
        printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \
                (ra).bus, (ra).target, (ra).lun, ##__VA_ARGS__)
@@ -1384,9 +1645,6 @@ struct ipr_ucode_image_header {
 #define ipr_ra_err(ioa_cfg, ra, fmt, ...) \
        ipr_ra_printk(KERN_ERR, ioa_cfg, ra, fmt, ##__VA_ARGS__)
 
-#define ipr_res_err(ioa_cfg, res, fmt, ...) \
-       ipr_ra_err(ioa_cfg, (res)->cfgte.res_addr, fmt, ##__VA_ARGS__)
-
 #define ipr_phys_res_err(ioa_cfg, res, fmt, ...)                       \
 {                                                                      \
        if ((res).bus >= IPR_MAX_NUM_BUSES) {                           \
@@ -1399,14 +1657,21 @@ struct ipr_ucode_image_header {
 }
 
 #define ipr_hcam_err(hostrcb, fmt, ...)                                        \
-{                                                                                                      \
-       if (ipr_is_device(&(hostrcb)->hcam.u.error.failing_dev_res_addr)) {             \
-               ipr_ra_err((hostrcb)->ioa_cfg,                                                  \
-                               (hostrcb)->hcam.u.error.failing_dev_res_addr,                   \
-                               fmt, ##__VA_ARGS__);                                                    \
-       } else {                                                                                        \
-               dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, ##__VA_ARGS__);            \
-       }                                                                                               \
+{                                                                      \
+       if (ipr_is_device(hostrcb)) {                                   \
+               if ((hostrcb)->ioa_cfg->sis64) {                        \
+                       printk(KERN_ERR IPR_NAME ": %s: " fmt,          \
+                               ipr_format_resource_path(&hostrcb->hcam.u.error64.fd_res_path[0], \
+                                       &hostrcb->rp_buffer[0]),        \
+                               __VA_ARGS__);                           \
+               } else {                                                \
+                       ipr_ra_err((hostrcb)->ioa_cfg,                  \
+                               (hostrcb)->hcam.u.error.fd_res_addr,    \
+                               fmt, __VA_ARGS__);                      \
+               }                                                       \
+       } else {                                                        \
+               dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, __VA_ARGS__); \
+       }                                                               \
 }
 
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
@@ -1432,7 +1697,7 @@ ipr_err("----------------------------------------------------------\n")
  **/
 static inline int ipr_is_ioa_resource(struct ipr_resource_entry *res)
 {
-       return (res->cfgte.flags & IPR_IS_IOA_RESOURCE) ? 1 : 0;
+       return res->type == IPR_RES_TYPE_IOAFP;
 }
 
 /**
@@ -1444,12 +1709,8 @@ static inline int ipr_is_ioa_resource(struct ipr_resource_entry *res)
  **/
 static inline int ipr_is_af_dasd_device(struct ipr_resource_entry *res)
 {
-       if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) &&
-           !ipr_is_ioa_resource(res) &&
-           IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_AF_DASD)
-               return 1;
-       else
-               return 0;
+       return res->type == IPR_RES_TYPE_AF_DASD ||
+               res->type == IPR_RES_TYPE_REMOTE_AF_DASD;
 }
 
 /**
@@ -1461,12 +1722,7 @@ static inline int ipr_is_af_dasd_device(struct ipr_resource_entry *res)
  **/
 static inline int ipr_is_vset_device(struct ipr_resource_entry *res)
 {
-       if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) &&
-           !ipr_is_ioa_resource(res) &&
-           IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_VOLUME_SET)
-               return 1;
-       else
-               return 0;
+       return res->type == IPR_RES_TYPE_VOLUME_SET;
 }
 
 /**
@@ -1478,11 +1734,7 @@ static inline int ipr_is_vset_device(struct ipr_resource_entry *res)
  **/
 static inline int ipr_is_gscsi(struct ipr_resource_entry *res)
 {
-       if (!ipr_is_ioa_resource(res) &&
-           IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_SCSI)
-               return 1;
-       else
-               return 0;
+       return res->type == IPR_RES_TYPE_GENERIC_SCSI;
 }
 
 /**
@@ -1495,7 +1747,7 @@ static inline int ipr_is_gscsi(struct ipr_resource_entry *res)
 static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res)
 {
        if (ipr_is_af_dasd_device(res) ||
-           (ipr_is_gscsi(res) && IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)))
+           (ipr_is_gscsi(res) && IPR_IS_DASD_DEVICE(res->std_inq_data)))
                return 1;
        else
                return 0;
@@ -1510,11 +1762,7 @@ static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res)
  **/
 static inline int ipr_is_gata(struct ipr_resource_entry *res)
 {
-       if (!ipr_is_ioa_resource(res) &&
-           IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_ATA)
-               return 1;
-       else
-               return 0;
+       return res->type == IPR_RES_TYPE_GENERIC_ATA;
 }
 
 /**
@@ -1526,24 +1774,35 @@ static inline int ipr_is_gata(struct ipr_resource_entry *res)
  **/
 static inline int ipr_is_naca_model(struct ipr_resource_entry *res)
 {
-       if (ipr_is_gscsi(res) && IPR_QUEUEING_MODEL(res) == IPR_QUEUE_NACA_MODEL)
+       if (ipr_is_gscsi(res) && res->qmodel == IPR_QUEUE_NACA_MODEL)
                return 1;
        return 0;
 }
 
 /**
- * ipr_is_device - Determine if resource address is that of a device
- * @res_addr:  resource address struct
+ * ipr_is_device - Determine if the hostrcb structure is related to a device
+ * @hostrcb:   host resource control blocks struct
  *
  * Return value:
  *     1 if AF / 0 if not AF
  **/
-static inline int ipr_is_device(struct ipr_res_addr *res_addr)
+static inline int ipr_is_device(struct ipr_hostrcb *hostrcb)
 {
-       if ((res_addr->bus < IPR_MAX_NUM_BUSES) &&
-           (res_addr->target < (IPR_MAX_NUM_TARGETS_PER_BUS - 1)))
-               return 1;
-
+       struct ipr_res_addr *res_addr;
+       u8 *res_path;
+
+       if (hostrcb->ioa_cfg->sis64) {
+               res_path = &hostrcb->hcam.u.error64.fd_res_path[0];
+               if ((res_path[0] == 0x00 || res_path[0] == 0x80 ||
+                   res_path[0] == 0x81) && res_path[2] != 0xFF)
+                       return 1;
+       } else {
+               res_addr = &hostrcb->hcam.u.error.fd_res_addr;
+
+               if ((res_addr->bus < IPR_MAX_NUM_BUSES) &&
+                   (res_addr->target < (IPR_MAX_NUM_TARGETS_PER_BUS - 1)))
+                       return 1;
+       }
        return 0;
 }
 
index 8a89ba9..249053a 100644 (file)
@@ -874,7 +874,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
        .cmd_per_lun            = ISCSI_DEF_CMD_PER_LUN,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler= iscsi_eh_device_reset,
-       .eh_target_reset_handler= iscsi_eh_target_reset,
+       .eh_target_reset_handler = iscsi_eh_recover_target,
        .use_clustering         = DISABLE_CLUSTERING,
        .slave_alloc            = iscsi_sw_tcp_slave_alloc,
        .slave_configure        = iscsi_sw_tcp_slave_configure,
index 703eb6a..685eaec 100644 (file)
@@ -2338,7 +2338,7 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
  * This function will wait for a relogin, session termination from
  * userspace, or a recovery/replacement timeout.
  */
-static int iscsi_eh_session_reset(struct scsi_cmnd *sc)
+int iscsi_eh_session_reset(struct scsi_cmnd *sc)
 {
        struct iscsi_cls_session *cls_session;
        struct iscsi_session *session;
@@ -2389,6 +2389,7 @@ failed:
        mutex_unlock(&session->eh_mutex);
        return SUCCESS;
 }
+EXPORT_SYMBOL_GPL(iscsi_eh_session_reset);
 
 static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
 {
@@ -2403,8 +2404,7 @@ static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
  * iscsi_eh_target_reset - reset target
  * @sc: scsi command
  *
- * This will attempt to send a warm target reset. If that fails
- * then we will drop the session and attempt ERL0 recovery.
+ * This will attempt to send a warm target reset.
  */
 int iscsi_eh_target_reset(struct scsi_cmnd *sc)
 {
@@ -2476,12 +2476,27 @@ done:
        ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
                     rc == SUCCESS ? "SUCCESS" : "FAILED");
        mutex_unlock(&session->eh_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
 
+/**
+ * iscsi_eh_recover_target - reset target and possibly the session
+ * @sc: scsi command
+ *
+ * This will attempt to send a warm target reset. If that fails,
+ * we will escalate to ERL0 session recovery.
+ */
+int iscsi_eh_recover_target(struct scsi_cmnd *sc)
+{
+       int rc;
+
+       rc = iscsi_eh_target_reset(sc);
        if (rc == FAILED)
                rc = iscsi_eh_session_reset(sc);
        return rc;
 }
-EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
+EXPORT_SYMBOL_GPL(iscsi_eh_recover_target);
 
 /*
  * Pre-allocate a pool of @max items of @item_size. By default, the pool
index 84b6964..565e16d 100644 (file)
@@ -37,6 +37,9 @@ struct lpfc_sli2_slim;
                                           the NameServer  before giving up. */
 #define LPFC_CMD_PER_LUN       3       /* max outstanding cmds per lun */
 #define LPFC_DEFAULT_SG_SEG_CNT 64     /* sg element count per scsi cmnd */
+#define LPFC_DEFAULT_MENLO_SG_SEG_CNT 128      /* sg element count per scsi
+               cmnd for menlo needs nearly twice as for firmware
+               downloads using bsg */
 #define LPFC_DEFAULT_PROT_SG_SEG_CNT 4096 /* sg protection elements count */
 #define LPFC_MAX_SG_SEG_CNT    4096    /* sg element count per scsi cmnd */
 #define LPFC_MAX_PROT_SG_SEG_CNT 4096  /* prot sg element count per scsi cmd*/
@@ -509,7 +512,6 @@ struct lpfc_hba {
        int (*lpfc_hba_down_link)
                (struct lpfc_hba *);
 
-
        /* SLI4 specific HBA data structure */
        struct lpfc_sli4_hba sli4_hba;
 
@@ -623,6 +625,9 @@ struct lpfc_hba {
        uint32_t cfg_log_verbose;
        uint32_t cfg_aer_support;
        uint32_t cfg_suppress_link_up;
+#define LPFC_INITIALIZE_LINK              0    /* do normal init_link mbox */
+#define LPFC_DELAY_INIT_LINK              1    /* layered driver hold off */
+#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2    /* wait, manual intervention */
 
        lpfc_vpd_t vpd;         /* vital product data */
 
@@ -804,6 +809,9 @@ struct lpfc_hba {
        struct list_head ct_ev_waiters;
        struct unsol_rcv_ct_ctx ct_ctx[64];
        uint32_t ctx_idx;
+
+       uint8_t menlo_flag;     /* menlo generic flags */
+#define HBA_MENLO_SUPPORT      0x1 /* HBA supports menlo commands */
 };
 
 static inline struct Scsi_Host *
index c992e83..64cd17e 100644 (file)
@@ -1939,7 +1939,9 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
 #            0x2  = never bring up link
 # Default value is 0.
 */
-LPFC_ATTR_R(suppress_link_up, 0, 0, 2, "Suppress Link Up at initialization");
+LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
+               LPFC_DELAY_INIT_LINK_INDEFINITELY,
+               "Suppress Link Up at initialization");
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1966,8 +1968,7 @@ lpfc_nodev_tmo_show(struct device *dev, struct device_attribute *attr,
 {
        struct Scsi_Host  *shost = class_to_shost(dev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       int val = 0;
-       val = vport->cfg_devloss_tmo;
+
        return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo);
 }
 
index f3f1bf1..692c29f 100644 (file)
@@ -83,15 +83,28 @@ struct lpfc_bsg_mbox {
        struct fc_bsg_job *set_job;
 };
 
+#define MENLO_DID 0x0000FC0E
+
+struct lpfc_bsg_menlo {
+       struct lpfc_iocbq *cmdiocbq;
+       struct lpfc_iocbq *rspiocbq;
+       struct lpfc_dmabuf *bmp;
+
+       /* job waiting for this iocb to finish */
+       struct fc_bsg_job *set_job;
+};
+
 #define TYPE_EVT       1
 #define TYPE_IOCB      2
 #define TYPE_MBOX      3
+#define TYPE_MENLO     4
 struct bsg_job_data {
        uint32_t type;
        union {
                struct lpfc_bsg_event *evt;
                struct lpfc_bsg_iocb iocb;
                struct lpfc_bsg_mbox mbox;
+               struct lpfc_bsg_menlo menlo;
        } context_un;
 };
 
@@ -2456,6 +2469,18 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
        case MBX_PORT_IOV_CONTROL:
                break;
        case MBX_SET_VARIABLE:
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "1226 mbox: set_variable 0x%x, 0x%x\n",
+                       mb->un.varWords[0],
+                       mb->un.varWords[1]);
+               if ((mb->un.varWords[0] == SETVAR_MLOMNT)
+                       && (mb->un.varWords[1] == 1)) {
+                       phba->wait_4_mlo_maint_flg = 1;
+               } else if (mb->un.varWords[0] == SETVAR_MLORST) {
+                       phba->link_flag &= ~LS_LOOPBACK_MODE;
+                       phba->fc_topology = TOPOLOGY_PT_PT;
+               }
+               break;
        case MBX_RUN_BIU_DIAG64:
        case MBX_READ_EVENT_LOG:
        case MBX_READ_SPARM64:
@@ -2638,6 +2663,297 @@ job_error:
 }
 
 /**
+ * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler
+ * @phba: Pointer to HBA context object.
+ * @cmdiocbq: Pointer to command iocb.
+ * @rspiocbq: Pointer to response iocb.
+ *
+ * This function is the completion handler for iocbs issued using
+ * lpfc_menlo_cmd function. This function is called by the
+ * ring event handler function without any lock held. This function
+ * can be called from both worker thread context and interrupt
+ * context. This function also can be called from another thread which
+ * cleans up the SLI layer objects.
+ * This function copies the contents of the response iocb to the
+ * response iocb memory object provided by the caller of
+ * lpfc_sli_issue_iocb_wait and then wakes up the thread which
+ * sleeps for the iocb completion.
+ **/
+static void
+lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
+                       struct lpfc_iocbq *cmdiocbq,
+                       struct lpfc_iocbq *rspiocbq)
+{
+       struct bsg_job_data *dd_data;
+       struct fc_bsg_job *job;
+       IOCB_t *rsp;
+       struct lpfc_dmabuf *bmp;
+       struct lpfc_bsg_menlo *menlo;
+       unsigned long flags;
+       struct menlo_response *menlo_resp;
+       int rc = 0;
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       dd_data = cmdiocbq->context1;
+       if (!dd_data) {
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               return;
+       }
+
+       menlo = &dd_data->context_un.menlo;
+       job = menlo->set_job;
+       job->dd_data = NULL; /* so timeout handler does not reply */
+
+       spin_lock_irqsave(&phba->hbalock, flags);
+       cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
+       if (cmdiocbq->context2 && rspiocbq)
+               memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
+                      &rspiocbq->iocb, sizeof(IOCB_t));
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
+       bmp = menlo->bmp;
+       rspiocbq = menlo->rspiocbq;
+       rsp = &rspiocbq->iocb;
+
+       pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+                    job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+                    job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+       /* always return the xri, this would be used in the case
+        * of a menlo download to allow the data to be sent as a continuation
+        * of the exchange.
+        */
+       menlo_resp = (struct menlo_response *)
+               job->reply->reply_data.vendor_reply.vendor_rsp;
+       menlo_resp->xri = rsp->ulpContext;
+       if (rsp->ulpStatus) {
+               if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                       switch (rsp->un.ulpWord[4] & 0xff) {
+                       case IOERR_SEQUENCE_TIMEOUT:
+                               rc = -ETIMEDOUT;
+                               break;
+                       case IOERR_INVALID_RPI:
+                               rc = -EFAULT;
+                               break;
+                       default:
+                               rc = -EACCES;
+                               break;
+                       }
+               } else
+                       rc = -EACCES;
+       } else
+               job->reply->reply_payload_rcv_len =
+                       rsp->un.genreq64.bdl.bdeSize;
+
+       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+       lpfc_sli_release_iocbq(phba, rspiocbq);
+       lpfc_sli_release_iocbq(phba, cmdiocbq);
+       kfree(bmp);
+       kfree(dd_data);
+       /* make error code available to userspace */
+       job->reply->result = rc;
+       /* complete the job back to userspace */
+       job->job_done(job);
+       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+       return;
+}
+
+/**
+ * lpfc_menlo_cmd - send an ioctl for menlo hardware
+ * @job: fc_bsg_job to handle
+ *
+ * This function issues a gen request 64 CR ioctl for all menlo cmd requests,
+ * all the command completions will return the xri for the command.
+ * For menlo data requests a gen request 64 CX is used to continue the exchange
+ * supplied in the menlo request header xri field.
+ **/
+static int
+lpfc_menlo_cmd(struct fc_bsg_job *job)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_iocbq *cmdiocbq, *rspiocbq;
+       IOCB_t *cmd, *rsp;
+       int rc = 0;
+       struct menlo_command *menlo_cmd;
+       struct menlo_response *menlo_resp;
+       struct lpfc_dmabuf *bmp = NULL;
+       int request_nseg;
+       int reply_nseg;
+       struct scatterlist *sgel = NULL;
+       int numbde;
+       dma_addr_t busaddr;
+       struct bsg_job_data *dd_data;
+       struct ulp_bde64 *bpl = NULL;
+
+       /* in case no data is returned return just the return code */
+       job->reply->reply_payload_rcv_len = 0;
+
+       if (job->request_len <
+           sizeof(struct fc_bsg_request) +
+               sizeof(struct menlo_command)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2784 Received MENLO_CMD request below "
+                               "minimum size\n");
+               rc = -ERANGE;
+               goto no_dd_data;
+       }
+
+       if (job->reply_len <
+           sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2785 Received MENLO_CMD reply below "
+                               "minimum size\n");
+               rc = -ERANGE;
+               goto no_dd_data;
+       }
+
+       if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2786 Adapter does not support menlo "
+                               "commands\n");
+               rc = -EPERM;
+               goto no_dd_data;
+       }
+
+       menlo_cmd = (struct menlo_command *)
+               job->request->rqst_data.h_vendor.vendor_cmd;
+
+       menlo_resp = (struct menlo_response *)
+               job->reply->reply_data.vendor_reply.vendor_rsp;
+
+       /* allocate our bsg tracking structure */
+       dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+       if (!dd_data) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2787 Failed allocation of dd_data\n");
+               rc = -ENOMEM;
+               goto no_dd_data;
+       }
+
+       bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!bmp) {
+               rc = -ENOMEM;
+               goto free_dd;
+       }
+
+       cmdiocbq = lpfc_sli_get_iocbq(phba);
+       if (!cmdiocbq) {
+               rc = -ENOMEM;
+               goto free_bmp;
+       }
+
+       rspiocbq = lpfc_sli_get_iocbq(phba);
+       if (!rspiocbq) {
+               rc = -ENOMEM;
+               goto free_cmdiocbq;
+       }
+
+       rsp = &rspiocbq->iocb;
+
+       bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+       if (!bmp->virt) {
+               rc = -ENOMEM;
+               goto free_rspiocbq;
+       }
+
+       INIT_LIST_HEAD(&bmp->list);
+       bpl = (struct ulp_bde64 *) bmp->virt;
+       request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
+                                 job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
+               busaddr = sg_dma_address(sgel);
+               bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+               bpl->tus.f.bdeSize = sg_dma_len(sgel);
+               bpl->tus.w = cpu_to_le32(bpl->tus.w);
+               bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+               bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+               bpl++;
+       }
+
+       reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
+                               job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+       for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
+               busaddr = sg_dma_address(sgel);
+               bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+               bpl->tus.f.bdeSize = sg_dma_len(sgel);
+               bpl->tus.w = cpu_to_le32(bpl->tus.w);
+               bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+               bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+               bpl++;
+       }
+
+       cmd = &cmdiocbq->iocb;
+       cmd->un.genreq64.bdl.ulpIoTag32 = 0;
+       cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
+       cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
+       cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+       cmd->un.genreq64.bdl.bdeSize =
+           (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
+       cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
+       cmd->un.genreq64.w5.hcsw.Dfctl = 0;
+       cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD;
+       cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */
+       cmd->ulpBdeCount = 1;
+       cmd->ulpClass = CLASS3;
+       cmd->ulpOwner = OWN_CHIP;
+       cmd->ulpLe = 1; /* Limited Edition */
+       cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+       cmdiocbq->vport = phba->pport;
+       /* We want the firmware to timeout before we do */
+       cmd->ulpTimeout = MENLO_TIMEOUT - 5;
+       cmdiocbq->context3 = bmp;
+       cmdiocbq->context2 = rspiocbq;
+       cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp;
+       cmdiocbq->context1 = dd_data;
+       cmdiocbq->context2 = rspiocbq;
+       if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) {
+               cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
+               cmd->ulpPU = MENLO_PU; /* 3 */
+               cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */
+               cmd->ulpContext = MENLO_CONTEXT; /* 0 */
+       } else {
+               cmd->ulpCommand = CMD_GEN_REQUEST64_CX;
+               cmd->ulpPU = 1;
+               cmd->un.ulpWord[4] = 0;
+               cmd->ulpContext = menlo_cmd->xri;
+       }
+
+       dd_data->type = TYPE_MENLO;
+       dd_data->context_un.menlo.cmdiocbq = cmdiocbq;
+       dd_data->context_un.menlo.rspiocbq = rspiocbq;
+       dd_data->context_un.menlo.set_job = job;
+       dd_data->context_un.menlo.bmp = bmp;
+
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
+               MENLO_TIMEOUT - 5);
+       if (rc == IOCB_SUCCESS)
+               return 0; /* done for now */
+
+       /* iocb failed so cleanup */
+       pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+                    job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+                    job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+
+free_rspiocbq:
+       lpfc_sli_release_iocbq(phba, rspiocbq);
+free_cmdiocbq:
+       lpfc_sli_release_iocbq(phba, cmdiocbq);
+free_bmp:
+       kfree(bmp);
+free_dd:
+       kfree(dd_data);
+no_dd_data:
+       /* make error code available to userspace */
+       job->reply->result = rc;
+       job->dd_data = NULL;
+       return rc;
+}
+/**
  * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
  * @job: fc_bsg_job to handle
  **/
@@ -2669,6 +2985,10 @@ lpfc_bsg_hst_vendor(struct fc_bsg_job *job)
        case LPFC_BSG_VENDOR_MBOX:
                rc = lpfc_bsg_mbox_cmd(job);
                break;
+       case LPFC_BSG_VENDOR_MENLO_CMD:
+       case LPFC_BSG_VENDOR_MENLO_DATA:
+               rc = lpfc_menlo_cmd(job);
+               break;
        default:
                rc = -EINVAL;
                job->reply->reply_payload_rcv_len = 0;
@@ -2728,6 +3048,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
        struct lpfc_bsg_event *evt;
        struct lpfc_bsg_iocb *iocb;
        struct lpfc_bsg_mbox *mbox;
+       struct lpfc_bsg_menlo *menlo;
        struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        struct bsg_job_data *dd_data;
        unsigned long flags;
@@ -2775,6 +3096,17 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                job->job_done(job);
                break;
+       case TYPE_MENLO:
+               menlo = &dd_data->context_un.menlo;
+               cmdiocb = menlo->cmdiocbq;
+               /* hint to completion handler that the job timed out */
+               job->reply->result = -EAGAIN;
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               /* this will call our completion handler */
+               spin_lock_irq(&phba->hbalock);
+               lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+               spin_unlock_irq(&phba->hbalock);
+               break;
        default:
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                break;
index 6c8f87e..5bc6308 100644 (file)
@@ -31,6 +31,8 @@
 #define LPFC_BSG_VENDOR_DIAG_TEST      5
 #define LPFC_BSG_VENDOR_GET_MGMT_REV   6
 #define LPFC_BSG_VENDOR_MBOX           7
+#define LPFC_BSG_VENDOR_MENLO_CMD      8
+#define LPFC_BSG_VENDOR_MENLO_DATA     9
 
 struct set_ct_event {
        uint32_t command;
@@ -96,3 +98,13 @@ struct dfc_mbox_req {
        uint8_t mbOffset;
 };
 
+/* Used for menlo command or menlo data. The xri is only used for menlo data */
+struct menlo_command {
+       uint32_t cmd;
+       uint32_t xri;
+};
+
+struct menlo_response {
+       uint32_t xri; /* return the xri of the iocb exchange */
+};
+
index 6f0fb51..5087c42 100644 (file)
@@ -63,6 +63,7 @@ void lpfc_linkdown_port(struct lpfc_vport *);
 void lpfc_port_link_failure(struct lpfc_vport *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
 
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -221,6 +222,10 @@ void lpfc_unregister_fcf_rescan(struct lpfc_hba *);
 void lpfc_unregister_unused_fcf(struct lpfc_hba *);
 int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);
 void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);
+void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
+uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
+int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
+void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
 
 int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
@@ -385,7 +390,7 @@ void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
 int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
 void lpfc_start_fdiscs(struct lpfc_hba *phba);
 struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t);
-
+struct lpfc_sglq *__lpfc_get_active_sglq(struct lpfc_hba *, uint16_t);
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
 #define HBA_EVENT_RSCN                   5
 #define HBA_EVENT_LINK_UP                2
index 2a40a6e..ee980bd 100644 (file)
@@ -771,6 +771,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct lpfc_nodelist *ndlp = cmdiocb->context1;
        struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
        struct serv_parm *sp;
+       uint16_t fcf_index;
        int rc;
 
        /* Check to see if link went down during discovery */
@@ -788,6 +789,54 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                vport->port_state);
 
        if (irsp->ulpStatus) {
+               /*
+                * In case of FIP mode, perform round robin FCF failover
+                * due to new FCF discovery
+                */
+               if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
+                   (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
+                                       "2611 FLOGI failed on registered "
+                                       "FCF record fcf_index:%d, trying "
+                                       "to perform round robin failover\n",
+                                       phba->fcf.current_rec.fcf_indx);
+                       fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
+                       if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
+                               /*
+                                * Exhausted the eligible FCF record list,
+                                * fail through to retry FLOGI on current
+                                * FCF record.
+                                */
+                               lpfc_printf_log(phba, KERN_WARNING,
+                                               LOG_FIP | LOG_ELS,
+                                               "2760 FLOGI exhausted FCF "
+                                               "round robin failover list, "
+                                               "retry FLOGI on the current "
+                                               "registered FCF index:%d\n",
+                                               phba->fcf.current_rec.fcf_indx);
+                               spin_lock_irq(&phba->hbalock);
+                               phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+                               spin_unlock_irq(&phba->hbalock);
+                       } else {
+                               rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
+                                                                  fcf_index);
+                               if (rc) {
+                                       lpfc_printf_log(phba, KERN_WARNING,
+                                                       LOG_FIP | LOG_ELS,
+                                                       "2761 FLOGI round "
+                                                       "robin FCF failover "
+                                                       "read FCF failed "
+                                                       "rc:x%x, fcf_index:"
+                                                       "%d\n", rc,
+                                               phba->fcf.current_rec.fcf_indx);
+                                       spin_lock_irq(&phba->hbalock);
+                                       phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+                                       spin_unlock_irq(&phba->hbalock);
+                               } else
+                                       goto out;
+                       }
+               }
+
                /* Check for retry */
                if (lpfc_els_retry(phba, cmdiocb, rspiocb))
                        goto out;
@@ -806,9 +855,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
 
                /* FLOGI failure */
-               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-                                "0100 FLOGI failure Data: x%x x%x "
-                                "x%x\n",
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
                                 irsp->ulpStatus, irsp->un.ulpWord[4],
                                 irsp->ulpTimeout);
                goto flogifail;
@@ -842,8 +890,18 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                else
                        rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
 
-               if (!rc)
+               if (!rc) {
+                       /* Mark the FCF discovery process done */
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS,
+                                        "2769 FLOGI successful on FCF record: "
+                                        "current_fcf_index:x%x, terminate FCF "
+                                        "round robin failover process\n",
+                                        phba->fcf.current_rec.fcf_indx);
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+                       spin_unlock_irq(&phba->hbalock);
                        goto out;
+               }
        }
 
 flogifail:
@@ -1409,6 +1467,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        goto out;
                }
                /* PLOGI failed */
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
+                                ndlp->nlp_DID, irsp->ulpStatus,
+                                irsp->un.ulpWord[4]);
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
                if (lpfc_error_lost_link(irsp))
                        rc = NLP_STE_FREED_NODE;
@@ -1577,6 +1639,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        goto out;
                }
                /* PRLI failed */
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "2754 PRLI failure DID:%06X Status:x%x/x%x\n",
+                                ndlp->nlp_DID, irsp->ulpStatus,
+                                irsp->un.ulpWord[4]);
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
                if (lpfc_error_lost_link(irsp))
                        goto out;
@@ -1860,6 +1926,10 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        goto out;
                }
                /* ADISC failed */
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "2755 ADISC failure DID:%06X Status:x%x/x%x\n",
+                                ndlp->nlp_DID, irsp->ulpStatus,
+                                irsp->un.ulpWord[4]);
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
                if (!lpfc_error_lost_link(irsp))
                        lpfc_disc_state_machine(vport, ndlp, cmdiocb,
@@ -2009,6 +2079,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        /* ELS command is being retried */
                        goto out;
                /* LOGO failed */
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "2756 LOGO failure DID:%06X Status:x%x/x%x\n",
+                                ndlp->nlp_DID, irsp->ulpStatus,
+                                irsp->un.ulpWord[4]);
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
                if (lpfc_error_lost_link(irsp))
                        goto out;
@@ -5989,7 +6063,12 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        if (phba->sli_rev < LPFC_SLI_REV4)
                                lpfc_issue_fabric_reglogin(vport);
                        else {
-                               lpfc_start_fdiscs(phba);
+                               /*
+                                * If the physical port is instantiated using
+                                * FDISC, do not start vport discovery.
+                                */
+                               if (vport->port_state != LPFC_FDISC)
+                                       lpfc_start_fdiscs(phba);
                                lpfc_do_scr_ns_plogi(phba, vport);
                        }
                } else
@@ -6055,21 +6134,18 @@ mbox_err_exit:
 }
 
 /**
- * lpfc_retry_pport_discovery - Start timer to retry FLOGI.
+ * lpfc_cancel_all_vport_retry_delay_timer - Cancel all vport retry delay timer
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine abort all pending discovery commands and
- * start a timer to retry FLOGI for the physical port
- * discovery.
+ * This routine cancels the retry delay timers to all the vports.
  **/
 void
-lpfc_retry_pport_discovery(struct lpfc_hba *phba)
+lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *phba)
 {
        struct lpfc_vport **vports;
        struct lpfc_nodelist *ndlp;
-       struct Scsi_Host  *shost;
-       int i;
        uint32_t link_state;
+       int i;
 
        /* Treat this failure as linkdown for all vports */
        link_state = phba->link_state;
@@ -6087,13 +6163,30 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba)
                }
                lpfc_destroy_vport_work_array(phba, vports);
        }
+}
+
+/**
+ * lpfc_retry_pport_discovery - Start timer to retry FLOGI.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine abort all pending discovery commands and
+ * start a timer to retry FLOGI for the physical port
+ * discovery.
+ **/
+void
+lpfc_retry_pport_discovery(struct lpfc_hba *phba)
+{
+       struct lpfc_nodelist *ndlp;
+       struct Scsi_Host  *shost;
+
+       /* Cancel the all vports retry delay retry timers */
+       lpfc_cancel_all_vport_retry_delay_timer(phba);
 
        /* If fabric require FLOGI, then re-instantiate physical login */
        ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
        if (!ndlp)
                return;
 
-
        shost = lpfc_shost_from_vport(phba->pport);
        mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
        spin_lock_irq(shost->host_lock);
@@ -6219,7 +6312,8 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-               vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
                spin_unlock_irq(shost->host_lock);
        }
 
@@ -6797,21 +6891,27 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
        struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
        unsigned long iflag = 0;
 
-       spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
        list_for_each_entry_safe(sglq_entry, sglq_next,
                        &phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
                if (sglq_entry->sli4_xritag == xri) {
                        list_del(&sglq_entry->list);
-                       spin_unlock_irqrestore(
-                                       &phba->sli4_hba.abts_sgl_list_lock,
-                                        iflag);
-                       spin_lock_irqsave(&phba->hbalock, iflag);
-
                        list_add_tail(&sglq_entry->list,
                                &phba->sli4_hba.lpfc_sgl_list);
+                       sglq_entry->state = SGL_FREED;
+                       spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
                        spin_unlock_irqrestore(&phba->hbalock, iflag);
                        return;
                }
        }
-       spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+       spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+       sglq_entry = __lpfc_get_active_sglq(phba, xri);
+       if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return;
+       }
+       sglq_entry->state = SGL_XRI_ABORTED;
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+       return;
 }
index 2359d0b..c555e3b 100644 (file)
@@ -1481,8 +1481,6 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
 int
 lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
 {
-       LPFC_MBOXQ_t *mbox;
-       int rc;
        /*
         * If the Link is up and no FCoE events while in the
         * FCF discovery, no need to restart FCF discovery.
@@ -1491,86 +1489,70 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
                (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
                return 0;
 
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "2768 Pending link or FCF event during current "
+                       "handling of the previous event: link_state:x%x, "
+                       "evt_tag_at_scan:x%x, evt_tag_current:x%x\n",
+                       phba->link_state, phba->fcoe_eventtag_at_fcf_scan,
+                       phba->fcoe_eventtag);
+
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag &= ~FCF_AVAILABLE;
        spin_unlock_irq(&phba->hbalock);
 
-       if (phba->link_state >= LPFC_LINK_UP)
-               lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
-       else {
+       if (phba->link_state >= LPFC_LINK_UP) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+                               "2780 Restart FCF table scan due to "
+                               "pending FCF event:evt_tag_at_scan:x%x, "
+                               "evt_tag_current:x%x\n",
+                               phba->fcoe_eventtag_at_fcf_scan,
+                               phba->fcoe_eventtag);
+               lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
+       } else {
                /*
                 * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
                 * flag
                 */
                spin_lock_irq(&phba->hbalock);
                phba->hba_flag &= ~FCF_DISC_INPROGRESS;
-               phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+               phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
                spin_unlock_irq(&phba->hbalock);
        }
 
+       /* Unregister the currently registered FCF if required */
        if (unreg_fcf) {
                spin_lock_irq(&phba->hbalock);
                phba->fcf.fcf_flag &= ~FCF_REGISTERED;
                spin_unlock_irq(&phba->hbalock);
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!mbox) {
-                       lpfc_printf_log(phba, KERN_ERR,
-                               LOG_DISCOVERY|LOG_MBOX,
-                               "2610 UNREG_FCFI mbox allocation failed\n");
-                       return 1;
-               }
-               lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
-               mbox->vport = phba->pport;
-               mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
-                               "2611 UNREG_FCFI issue mbox failed\n");
-                       mempool_free(mbox, phba->mbox_mem_pool);
-               }
+               lpfc_sli4_unregister_fcf(phba);
        }
-
        return 1;
 }
 
 /**
- * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
+ * @next_fcf_index: pointer to holder of next fcf index.
  *
- * This function iterate through all the fcf records available in
- * HBA and choose the optimal FCF record for discovery. After finding
- * the FCF for discovery it register the FCF record and kick start
- * discovery.
- * If FCF_IN_USE flag is set in currently used FCF, the routine try to
- * use a FCF record which match fabric name and mac address of the
- * currently used FCF record.
- * If the driver support only one FCF, it will try to use the FCF record
- * used by BOOT_BIOS.
+ * This routine parses the non-embedded fcf mailbox command by performing the
+ * necessarily error checking, non-embedded read FCF record mailbox command
+ * SGE parsing, and endianness swapping.
+ *
+ * Returns the pointer to the new FCF record in the non-embedded mailbox
+ * command DMA memory if successfully, other NULL.
  */
-void
-lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+static struct fcf_record *
+lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
+                            uint16_t *next_fcf_index)
 {
        void *virt_addr;
        dma_addr_t phys_addr;
-       uint8_t *bytep;
        struct lpfc_mbx_sge sge;
        struct lpfc_mbx_read_fcf_tbl *read_fcf;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
        struct fcf_record *new_fcf_record;
-       uint32_t boot_flag, addr_mode;
-       uint32_t next_fcf_index;
-       struct lpfc_fcf_rec *fcf_rec = NULL;
-       unsigned long iflags;
-       uint16_t vlan_id;
-       int rc;
-
-       /* If there is pending FCoE event restart FCF table scan */
-       if (lpfc_check_pending_fcoe_event(phba, 0)) {
-               lpfc_sli4_mbox_cmd_free(phba, mboxq);
-               return;
-       }
 
        /* Get the first SGE entry from the non-embedded DMA memory. This
         * routine only uses a single SGE.
@@ -1581,59 +1563,183 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
                                "2524 Failed to get the non-embedded SGE "
                                "virtual address\n");
-               goto out;
+               return NULL;
        }
        virt_addr = mboxq->sge_array->addr[0];
 
        shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
        shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
-       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
-                                &shdr->response);
-       /*
-        * The FCF Record was read and there is no reason for the driver
-        * to maintain the FCF record data or memory. Instead, just need
-        * to book keeping the FCFIs can be used.
-        */
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
        if (shdr_status || shdr_add_status) {
-               if (shdr_status == STATUS_FCF_TABLE_EMPTY) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+               if (shdr_status == STATUS_FCF_TABLE_EMPTY)
+                       lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                        "2726 READ_FCF_RECORD Indicates empty "
                                        "FCF table.\n");
-               } else {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+               else
+                       lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                        "2521 READ_FCF_RECORD mailbox failed "
-                                       "with status x%x add_status x%x, mbx\n",
-                                       shdr_status, shdr_add_status);
-               }
-               goto out;
+                                       "with status x%x add_status x%x, "
+                                       "mbx\n", shdr_status, shdr_add_status);
+               return NULL;
        }
-       /* Interpreting the returned information of FCF records */
+
+       /* Interpreting the returned information of the FCF record */
        read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
        lpfc_sli_pcimem_bcopy(read_fcf, read_fcf,
                              sizeof(struct lpfc_mbx_read_fcf_tbl));
-       next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf);
-
+       *next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf);
        new_fcf_record = (struct fcf_record *)(virt_addr +
                          sizeof(struct lpfc_mbx_read_fcf_tbl));
        lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
                              sizeof(struct fcf_record));
-       bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
 
+       return new_fcf_record;
+}
+
+/**
+ * lpfc_sli4_log_fcf_record_info - Log the information of a fcf record
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_record: pointer to the fcf record.
+ * @vlan_id: the lowest vlan identifier associated to this fcf record.
+ * @next_fcf_index: the index to the next fcf record in hba's fcf table.
+ *
+ * This routine logs the detailed FCF record if the LOG_FIP loggin is
+ * enabled.
+ **/
+static void
+lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba,
+                             struct fcf_record *fcf_record,
+                             uint16_t vlan_id,
+                             uint16_t next_fcf_index)
+{
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "2764 READ_FCF_RECORD:\n"
+                       "\tFCF_Index     : x%x\n"
+                       "\tFCF_Avail     : x%x\n"
+                       "\tFCF_Valid     : x%x\n"
+                       "\tFIP_Priority  : x%x\n"
+                       "\tMAC_Provider  : x%x\n"
+                       "\tLowest VLANID : x%x\n"
+                       "\tFCF_MAC Addr  : x%x:%x:%x:%x:%x:%x\n"
+                       "\tFabric_Name   : x%x:%x:%x:%x:%x:%x:%x:%x\n"
+                       "\tSwitch_Name   : x%x:%x:%x:%x:%x:%x:%x:%x\n"
+                       "\tNext_FCF_Index: x%x\n",
+                       bf_get(lpfc_fcf_record_fcf_index, fcf_record),
+                       bf_get(lpfc_fcf_record_fcf_avail, fcf_record),
+                       bf_get(lpfc_fcf_record_fcf_valid, fcf_record),
+                       fcf_record->fip_priority,
+                       bf_get(lpfc_fcf_record_mac_addr_prov, fcf_record),
+                       vlan_id,
+                       bf_get(lpfc_fcf_record_mac_0, fcf_record),
+                       bf_get(lpfc_fcf_record_mac_1, fcf_record),
+                       bf_get(lpfc_fcf_record_mac_2, fcf_record),
+                       bf_get(lpfc_fcf_record_mac_3, fcf_record),
+                       bf_get(lpfc_fcf_record_mac_4, fcf_record),
+                       bf_get(lpfc_fcf_record_mac_5, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_0, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_1, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_2, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_3, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_4, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_5, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_6, fcf_record),
+                       bf_get(lpfc_fcf_record_fab_name_7, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_0, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_1, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_2, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_3, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_4, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_5, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_6, fcf_record),
+                       bf_get(lpfc_fcf_record_switch_name_7, fcf_record),
+                       next_fcf_index);
+}
+
+/**
+ * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object.
+ *
+ * This function iterates through all the fcf records available in
+ * HBA and chooses the optimal FCF record for discovery. After finding
+ * the FCF for discovery it registers the FCF record and kicks start
+ * discovery.
+ * If FCF_IN_USE flag is set in currently used FCF, the routine tries to
+ * use an FCF record which matches fabric name and mac address of the
+ * currently used FCF record.
+ * If the driver supports only one FCF, it will try to use the FCF record
+ * used by BOOT_BIOS.
+ */
+void
+lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct fcf_record *new_fcf_record;
+       uint32_t boot_flag, addr_mode;
+       uint16_t fcf_index, next_fcf_index;
+       struct lpfc_fcf_rec *fcf_rec = NULL;
+       uint16_t vlan_id;
+       int rc;
+
+       /* If there is pending FCoE event restart FCF table scan */
+       if (lpfc_check_pending_fcoe_event(phba, 0)) {
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return;
+       }
+
+       /* Parse the FCF record from the non-embedded mailbox command */
+       new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
+                                                     &next_fcf_index);
+       if (!new_fcf_record) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                               "2765 Mailbox command READ_FCF_RECORD "
+                               "failed to retrieve a FCF record.\n");
+               /* Let next new FCF event trigger fast failover */
+               spin_lock_irq(&phba->hbalock);
+               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               spin_unlock_irq(&phba->hbalock);
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return;
+       }
+
+       /* Check the FCF record against the connection list */
        rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
                                      &addr_mode, &vlan_id);
+
+       /* Log the FCF record information if turned on */
+       lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
+                                     next_fcf_index);
+
        /*
         * If the fcf record does not match with connect list entries
-        * read the next entry.
+        * read the next entry; otherwise, this is an eligible FCF
+        * record for round robin FCF failover.
         */
-       if (!rc)
+       if (!rc) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                               "2781 FCF record fcf_index:x%x failed FCF "
+                               "connection list check, fcf_avail:x%x, "
+                               "fcf_valid:x%x\n",
+                               bf_get(lpfc_fcf_record_fcf_index,
+                                      new_fcf_record),
+                               bf_get(lpfc_fcf_record_fcf_avail,
+                                      new_fcf_record),
+                               bf_get(lpfc_fcf_record_fcf_valid,
+                                      new_fcf_record));
                goto read_next_fcf;
+       } else {
+               fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+               rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+               if (rc)
+                       goto read_next_fcf;
+       }
+
        /*
         * If this is not the first FCF discovery of the HBA, use last
         * FCF record for the discovery. The condition that a rescan
         * matches the in-use FCF record: fabric name, switch name, mac
         * address, and vlan_id.
         */
-       spin_lock_irqsave(&phba->hbalock, iflags);
+       spin_lock_irq(&phba->hbalock);
        if (phba->fcf.fcf_flag & FCF_IN_USE) {
                if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
                                        new_fcf_record) &&
@@ -1649,8 +1755,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
                        else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
                                /* If in fast failover, mark it's completed */
-                               phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
-                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                               phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV |
+                                                       FCF_DISCOVERY);
+                       spin_unlock_irq(&phba->hbalock);
                        goto out;
                }
                /*
@@ -1661,7 +1768,7 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                 * next candidate.
                 */
                if (!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
-                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                       spin_unlock_irq(&phba->hbalock);
                        goto read_next_fcf;
                }
        }
@@ -1669,14 +1776,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         * Update on failover FCF record only if it's in FCF fast-failover
         * period; otherwise, update on current FCF record.
         */
-       if (phba->fcf.fcf_flag & FCF_REDISC_FOV) {
-               /* Fast FCF failover only to the same fabric name */
-               if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
-                                       new_fcf_record))
-                       fcf_rec = &phba->fcf.failover_rec;
-               else
-                       goto read_next_fcf;
-       } else
+       if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
+               fcf_rec = &phba->fcf.failover_rec;
+       else
                fcf_rec = &phba->fcf.current_rec;
 
        if (phba->fcf.fcf_flag & FCF_AVAILABLE) {
@@ -1689,7 +1791,7 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                        /* Choose this FCF record */
                        __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
                                        addr_mode, vlan_id, BOOT_ENABLE);
-                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                       spin_unlock_irq(&phba->hbalock);
                        goto read_next_fcf;
                }
                /*
@@ -1698,20 +1800,19 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                 * the next FCF record.
                 */
                if (!boot_flag && (fcf_rec->flag & BOOT_ENABLE)) {
-                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                       spin_unlock_irq(&phba->hbalock);
                        goto read_next_fcf;
                }
                /*
                 * If the new hba FCF record has lower priority value
                 * than the driver FCF record, use the new record.
                 */
-               if (lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record) &&
-                   (new_fcf_record->fip_priority < fcf_rec->priority)) {
+               if (new_fcf_record->fip_priority < fcf_rec->priority) {
                        /* Choose this FCF record */
                        __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
                                        addr_mode, vlan_id, 0);
                }
-               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               spin_unlock_irq(&phba->hbalock);
                goto read_next_fcf;
        }
        /*
@@ -1724,7 +1825,7 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                         BOOT_ENABLE : 0));
                phba->fcf.fcf_flag |= FCF_AVAILABLE;
        }
-       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       spin_unlock_irq(&phba->hbalock);
        goto read_next_fcf;
 
 read_next_fcf:
@@ -1740,9 +1841,22 @@ read_next_fcf:
                         * FCF scan inprogress, and do nothing
                         */
                        if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) {
-                               spin_lock_irqsave(&phba->hbalock, iflags);
+                               lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                                              "2782 No suitable FCF record "
+                                              "found during this round of "
+                                              "post FCF rediscovery scan: "
+                                              "fcf_evt_tag:x%x, fcf_index: "
+                                              "x%x\n",
+                                              phba->fcoe_eventtag_at_fcf_scan,
+                                              bf_get(lpfc_fcf_record_fcf_index,
+                                                     new_fcf_record));
+                               /*
+                                * Let next new FCF event trigger fast
+                                * failover
+                                */
+                               spin_lock_irq(&phba->hbalock);
                                phba->hba_flag &= ~FCF_DISC_INPROGRESS;
-                               spin_unlock_irqrestore(&phba->hbalock, iflags);
+                               spin_unlock_irq(&phba->hbalock);
                                return;
                        }
                        /*
@@ -1754,16 +1868,23 @@ read_next_fcf:
                         * record.
                         */
 
-                       /* unregister the current in-use FCF record */
+                       /* Unregister the current in-use FCF record */
                        lpfc_unregister_fcf(phba);
-                       /* replace in-use record with the new record */
+
+                       /* Replace in-use record with the new record */
                        memcpy(&phba->fcf.current_rec,
                               &phba->fcf.failover_rec,
                               sizeof(struct lpfc_fcf_rec));
                        /* mark the FCF fast failover completed */
-                       spin_lock_irqsave(&phba->hbalock, iflags);
+                       spin_lock_irq(&phba->hbalock);
                        phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
-                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * Set up the initial registered FCF index for FLOGI
+                        * round robin FCF failover.
+                        */
+                       phba->fcf.fcf_rr_init_indx =
+                                       phba->fcf.failover_rec.fcf_indx;
                        /* Register to the new FCF record */
                        lpfc_register_fcf(phba);
                } else {
@@ -1776,13 +1897,25 @@ read_next_fcf:
                                return;
                        /*
                         * Otherwise, initial scan or post linkdown rescan,
-                        * register with the best fit FCF record found so
-                        * far through the scanning process.
+                        * register with the best FCF record found so far
+                        * through the FCF scanning process.
+                        */
+
+                       /* mark the initial FCF discovery completed */
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * Set up the initial registered FCF index for FLOGI
+                        * round robin FCF failover
                         */
+                       phba->fcf.fcf_rr_init_indx =
+                                       phba->fcf.current_rec.fcf_indx;
+                       /* Register to the new FCF record */
                        lpfc_register_fcf(phba);
                }
        } else
-               lpfc_sli4_read_fcf_record(phba, next_fcf_index);
+               lpfc_sli4_fcf_scan_read_fcf_rec(phba, next_fcf_index);
        return;
 
 out:
@@ -1793,6 +1926,141 @@ out:
 }
 
 /**
+ * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf round robin read_fcf mbox cmpl hdler
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object.
+ *
+ * This is the callback function for FLOGI failure round robin FCF failover
+ * read FCF record mailbox command from the eligible FCF record bmask for
+ * performing the failover. If the FCF read back is not valid/available, it
+ * fails through to retrying FLOGI to the currently registered FCF again.
+ * Otherwise, if the FCF read back is valid and available, it will set the
+ * newly read FCF record to the failover FCF record, unregister currently
+ * registered FCF record, copy the failover FCF record to the current
+ * FCF record, and then register the current FCF record before proceeding
+ * to trying FLOGI on the new failover FCF.
+ */
+void
+lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct fcf_record *new_fcf_record;
+       uint32_t boot_flag, addr_mode;
+       uint16_t next_fcf_index;
+       uint16_t current_fcf_index;
+       uint16_t vlan_id;
+
+       /* If link state is not up, stop the round robin failover process */
+       if (phba->link_state < LPFC_LINK_UP) {
+               spin_lock_irq(&phba->hbalock);
+               phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+               spin_unlock_irq(&phba->hbalock);
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return;
+       }
+
+       /* Parse the FCF record from the non-embedded mailbox command */
+       new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
+                                                     &next_fcf_index);
+       if (!new_fcf_record) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                               "2766 Mailbox command READ_FCF_RECORD "
+                               "failed to retrieve a FCF record.\n");
+               goto out;
+       }
+
+       /* Get the needed parameters from FCF record */
+       lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
+                                &addr_mode, &vlan_id);
+
+       /* Log the FCF record information if turned on */
+       lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
+                                     next_fcf_index);
+
+       /* Upload new FCF record to the failover FCF record */
+       spin_lock_irq(&phba->hbalock);
+       __lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
+                                new_fcf_record, addr_mode, vlan_id,
+                                (boot_flag ? BOOT_ENABLE : 0));
+       spin_unlock_irq(&phba->hbalock);
+
+       current_fcf_index = phba->fcf.current_rec.fcf_indx;
+
+       /* Unregister the current in-use FCF record */
+       lpfc_unregister_fcf(phba);
+
+       /* Replace in-use record with the new record */
+       memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec,
+              sizeof(struct lpfc_fcf_rec));
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "2783 FLOGI round robin FCF failover from FCF "
+                       "(index:x%x) to FCF (index:x%x).\n",
+                       current_fcf_index,
+                       bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
+
+out:
+       lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       lpfc_register_fcf(phba);
+}
+
+/**
+ * lpfc_mbx_cmpl_read_fcf_rec - read fcf completion handler.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object.
+ *
+ * This is the callback function of read FCF record mailbox command for
+ * updating the eligible FCF bmask for FLOGI failure round robin FCF
+ * failover when a new FCF event happened. If the FCF read back is
+ * valid/available and it passes the connection list check, it updates
+ * the bmask for the eligible FCF record for round robin failover.
+ */
+void
+lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct fcf_record *new_fcf_record;
+       uint32_t boot_flag, addr_mode;
+       uint16_t fcf_index, next_fcf_index;
+       uint16_t vlan_id;
+       int rc;
+
+       /* If link state is not up, no need to proceed */
+       if (phba->link_state < LPFC_LINK_UP)
+               goto out;
+
+       /* If FCF discovery period is over, no need to proceed */
+       if (phba->fcf.fcf_flag & FCF_DISCOVERY)
+               goto out;
+
+       /* Parse the FCF record from the non-embedded mailbox command */
+       new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
+                                                     &next_fcf_index);
+       if (!new_fcf_record) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2767 Mailbox command READ_FCF_RECORD "
+                               "failed to retrieve a FCF record.\n");
+               goto out;
+       }
+
+       /* Check the connection list for eligibility */
+       rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
+                                     &addr_mode, &vlan_id);
+
+       /* Log the FCF record information if turned on */
+       lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
+                                     next_fcf_index);
+
+       if (!rc)
+               goto out;
+
+       /* Update the eligible FCF record index bmask */
+       fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+       rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+
+out:
+       lpfc_sli4_mbox_cmd_free(phba, mboxq);
+}
+
+/**
  * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox data structure.
@@ -2024,8 +2292,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
        int rc;
        struct fcf_record *fcf_record;
 
-       sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-
        spin_lock_irq(&phba->hbalock);
        switch (la->UlnkSpeed) {
        case LA_1GHZ_LINK:
@@ -2117,18 +2383,24 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
        spin_unlock_irq(&phba->hbalock);
 
        lpfc_linkup(phba);
-       if (sparam_mbox) {
-               lpfc_read_sparam(phba, sparam_mbox, 0);
-               sparam_mbox->vport = vport;
-               sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
-               rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
-                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
-                       kfree(mp);
-                       mempool_free(sparam_mbox, phba->mbox_mem_pool);
-                       goto out;
-               }
+       sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!sparam_mbox)
+               goto out;
+
+       rc = lpfc_read_sparam(phba, sparam_mbox, 0);
+       if (rc) {
+               mempool_free(sparam_mbox, phba->mbox_mem_pool);
+               goto out;
+       }
+       sparam_mbox->vport = vport;
+       sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
+       rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
+               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+               kfree(mp);
+               mempool_free(sparam_mbox, phba->mbox_mem_pool);
+               goto out;
        }
 
        if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
@@ -2186,10 +2458,20 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                        spin_unlock_irq(&phba->hbalock);
                        return;
                }
+               /* This is the initial FCF discovery scan */
+               phba->fcf.fcf_flag |= FCF_INIT_DISC;
                spin_unlock_irq(&phba->hbalock);
-               rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
-               if (rc)
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+                               "2778 Start FCF table scan at linkup\n");
+
+               rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+                                                    LPFC_FCOE_FCF_GET_FIRST);
+               if (rc) {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+                       spin_unlock_irq(&phba->hbalock);
                        goto out;
+               }
        }
 
        return;
@@ -3379,8 +3661,12 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
                shost = lpfc_shost_from_vport(vports[i]);
                spin_lock_irq(shost->host_lock);
                list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
-                       if (ndlp->nlp_flag & NLP_RPI_VALID)
+                       if (ndlp->nlp_flag & NLP_RPI_VALID) {
+                               /* The mempool_alloc might sleep */
+                               spin_unlock_irq(shost->host_lock);
                                lpfc_unreg_rpi(vports[i], ndlp);
+                               spin_lock_irq(shost->host_lock);
+                       }
                }
                spin_unlock_irq(shost->host_lock);
        }
@@ -4756,6 +5042,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
                return;
        /* Reset HBA FCF states after successful unregister FCF */
        phba->fcf.fcf_flag = 0;
+       phba->fcf.current_rec.flag = 0;
 
        /*
         * If driver is not unloading, check if there is any other
@@ -4765,13 +5052,21 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
            (phba->link_state < LPFC_LINK_UP))
                return;
 
-       rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+       /* This is considered as the initial FCF discovery scan */
+       spin_lock_irq(&phba->hbalock);
+       phba->fcf.fcf_flag |= FCF_INIT_DISC;
+       spin_unlock_irq(&phba->hbalock);
+       rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
 
-       if (rc)
+       if (rc) {
+               spin_lock_irq(&phba->hbalock);
+               phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+               spin_unlock_irq(&phba->hbalock);
                lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
                                "2553 lpfc_unregister_unused_fcf failed "
                                "to read FCF record HBA state x%x\n",
                                phba->pport->port_state);
+       }
 }
 
 /**
index d29ac7c..ea44239 100644 (file)
@@ -350,7 +350,12 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        mb = &pmb->u.mb;
 
        /* Get login parameters for NID.  */
-       lpfc_read_sparam(phba, pmb, 0);
+       rc = lpfc_read_sparam(phba, pmb, 0);
+       if (rc) {
+               mempool_free(pmb, phba->mbox_mem_pool);
+               return -ENOMEM;
+       }
+
        pmb->vport = vport;
        if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -359,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                                mb->mbxCommand, mb->mbxStatus);
                phba->link_state = LPFC_HBA_ERROR;
                mp = (struct lpfc_dmabuf *) pmb->context1;
-               mempool_free( pmb, phba->mbox_mem_pool);
+               mempool_free(pmb, phba->mbox_mem_pool);
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
                return -EIO;
@@ -544,7 +549,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                        mempool_free(pmb, phba->mbox_mem_pool);
                        return -EIO;
                }
-       } else if (phba->cfg_suppress_link_up == 0) {
+       } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) {
                lpfc_init_link(phba, pmb, phba->cfg_topology,
                        phba->cfg_link_speed);
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -571,6 +576,11 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        }
        /* MBOX buffer will be freed in mbox compl */
        pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return -ENOMEM;
+       }
+
        lpfc_config_async(phba, pmb, LPFC_ELS_RING);
        pmb->mbox_cmpl = lpfc_config_async_cmpl;
        pmb->vport = phba->pport;
@@ -588,6 +598,11 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
        /* Get Option rom version */
        pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return -ENOMEM;
+       }
+
        lpfc_dump_wakeup_param(phba, pmb);
        pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl;
        pmb->vport = phba->pport;
@@ -652,7 +667,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
                        mempool_free(pmb, phba->mbox_mem_pool);
                return -EIO;
        }
-       phba->cfg_suppress_link_up = 0;
+       phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
 
        return 0;
 }
@@ -807,6 +822,8 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
        LIST_HEAD(aborts);
        int ret;
        unsigned long iflag = 0;
+       struct lpfc_sglq *sglq_entry = NULL;
+
        ret = lpfc_hba_down_post_s3(phba);
        if (ret)
                return ret;
@@ -822,6 +839,10 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
         * list.
         */
        spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
+       list_for_each_entry(sglq_entry,
+               &phba->sli4_hba.lpfc_abts_els_sgl_list, list)
+               sglq_entry->state = SGL_FREED;
+
        list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list,
                        &phba->sli4_hba.lpfc_sgl_list);
        spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
@@ -2178,8 +2199,10 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
 void
 __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
 {
-       /* Clear pending FCF rediscovery wait timer */
-       phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
+       /* Clear pending FCF rediscovery wait and failover in progress flags */
+       phba->fcf.fcf_flag &= ~(FCF_REDISC_PEND |
+                               FCF_DEAD_DISC |
+                               FCF_ACVL_DISC);
        /* Now, try to stop the timer */
        del_timer(&phba->fcf.redisc_wait);
 }
@@ -2576,6 +2599,14 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        init_timer(&vport->els_tmofunc);
        vport->els_tmofunc.function = lpfc_els_timeout;
        vport->els_tmofunc.data = (unsigned long)vport;
+       if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
+               phba->menlo_flag |= HBA_MENLO_SUPPORT;
+               /* check for menlo minimum sg count */
+               if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) {
+                       phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
+                       shost->sg_tablesize = phba->cfg_sg_seg_cnt;
+               }
+       }
 
        error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
        if (error)
@@ -2912,6 +2943,9 @@ lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr)
        /* FCF rediscovery event to worker thread */
        phba->fcf.fcf_flag |= FCF_REDISC_EVT;
        spin_unlock_irq(&phba->hbalock);
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "2776 FCF rediscover wait timer expired, post "
+                       "a worker thread event for FCF table scan\n");
        /* wake up worker thread */
        lpfc_worker_wake_up(phba);
 }
@@ -3183,6 +3217,68 @@ out_free_pmb:
 }
 
 /**
+ * lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport
+ * @vport: pointer to vport data structure.
+ *
+ * This routine is to perform Clear Virtual Link (CVL) on a vport in
+ * response to a CVL event.
+ *
+ * Return the pointer to the ndlp with the vport if successful, otherwise
+ * return NULL.
+ **/
+static struct lpfc_nodelist *
+lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
+{
+       struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost;
+       struct lpfc_hba *phba;
+
+       if (!vport)
+               return NULL;
+       ndlp = lpfc_findnode_did(vport, Fabric_DID);
+       if (!ndlp)
+               return NULL;
+       phba = vport->phba;
+       if (!phba)
+               return NULL;
+       if (phba->pport->port_state <= LPFC_FLOGI)
+               return NULL;
+       /* If virtual link is not yet instantiated ignore CVL */
+       if (vport->port_state <= LPFC_FDISC)
+               return NULL;
+       shost = lpfc_shost_from_vport(vport);
+       if (!shost)
+               return NULL;
+       lpfc_linkdown_port(vport);
+       lpfc_cleanup_pending_mbox(vport);
+       spin_lock_irq(shost->host_lock);
+       vport->fc_flag |= FC_VPORT_CVL_RCVD;
+       spin_unlock_irq(shost->host_lock);
+
+       return ndlp;
+}
+
+/**
+ * lpfc_sli4_perform_all_vport_cvl - Perform clear virtual link on all vports
+ * @vport: pointer to lpfc hba data structure.
+ *
+ * This routine is to perform Clear Virtual Link (CVL) on all vports in
+ * response to a FCF dead event.
+ **/
+static void
+lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
+{
+       struct lpfc_vport **vports;
+       int i;
+
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports)
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+                       lpfc_sli4_perform_vport_cvl(vports[i]);
+       lpfc_destroy_vport_work_array(phba, vports);
+}
+
+/**
  * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
  * @phba: pointer to lpfc hba data structure.
  * @acqe_link: pointer to the async fcoe completion queue entry.
@@ -3198,7 +3294,6 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
        struct lpfc_vport *vport;
        struct lpfc_nodelist *ndlp;
        struct Scsi_Host  *shost;
-       uint32_t link_state;
        int active_vlink_present;
        struct lpfc_vport **vports;
        int i;
@@ -3208,10 +3303,11 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
        switch (event_type) {
        case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
        case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
-               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-                       "2546 New FCF found index 0x%x tag 0x%x\n",
-                       acqe_fcoe->index,
-                       acqe_fcoe->event_tag);
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
+                       "2546 New FCF found/FCF parameter modified event: "
+                       "evt_tag:x%x, fcf_index:x%x\n",
+                       acqe_fcoe->event_tag, acqe_fcoe->index);
+
                spin_lock_irq(&phba->hbalock);
                if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
                    (phba->hba_flag & FCF_DISC_INPROGRESS)) {
@@ -3222,6 +3318,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                        spin_unlock_irq(&phba->hbalock);
                        break;
                }
+
                if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
                        /*
                         * If fast FCF failover rescan event is pending,
@@ -3232,12 +3329,33 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                }
                spin_unlock_irq(&phba->hbalock);
 
-               /* Read the FCF table and re-discover SAN. */
-               rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+               if ((phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+                   !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+                       /*
+                        * During period of FCF discovery, read the FCF
+                        * table record indexed by the event to update
+                        * FCF round robin failover eligible FCF bmask.
+                        */
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
+                                       LOG_DISCOVERY,
+                                       "2779 Read new FCF record with "
+                                       "fcf_index:x%x for updating FCF "
+                                       "round robin failover bmask\n",
+                                       acqe_fcoe->index);
+                       rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
+               }
+
+               /* Otherwise, scan the entire FCF table and re-discover SAN */
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+                               "2770 Start FCF table scan due to new FCF "
+                               "event: evt_tag:x%x, fcf_index:x%x\n",
+                               acqe_fcoe->event_tag, acqe_fcoe->index);
+               rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+                                                    LPFC_FCOE_FCF_GET_FIRST);
                if (rc)
-                       lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-                                       "2547 Read FCF record failed 0x%x\n",
-                                       rc);
+                       lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
+                                       "2547 Issue FCF scan read FCF mailbox "
+                                       "command failed 0x%x\n", rc);
                break;
 
        case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
@@ -3248,47 +3366,63 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                break;
 
        case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
-               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
                        "2549 FCF disconnected from network index 0x%x"
                        " tag 0x%x\n", acqe_fcoe->index,
                        acqe_fcoe->event_tag);
                /* If the event is not for currently used fcf do nothing */
                if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index)
                        break;
-               /*
-                * Currently, driver support only one FCF - so treat this as
-                * a link down, but save the link state because we don't want
-                * it to be changed to Link Down unless it is already down.
+               /* We request port to rediscover the entire FCF table for
+                * a fast recovery from case that the current FCF record
+                * is no longer valid if we are not in the middle of FCF
+                * failover process already.
                 */
-               link_state = phba->link_state;
-               lpfc_linkdown(phba);
-               phba->link_state = link_state;
-               /* Unregister FCF if no devices connected to it */
-               lpfc_unregister_unused_fcf(phba);
+               spin_lock_irq(&phba->hbalock);
+               if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
+                       spin_unlock_irq(&phba->hbalock);
+                       /* Update FLOGI FCF failover eligible FCF bmask */
+                       lpfc_sli4_fcf_rr_index_clear(phba, acqe_fcoe->index);
+                       break;
+               }
+               /* Mark the fast failover process in progress */
+               phba->fcf.fcf_flag |= FCF_DEAD_DISC;
+               spin_unlock_irq(&phba->hbalock);
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+                               "2771 Start FCF fast failover process due to "
+                               "FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
+                               "\n", acqe_fcoe->event_tag, acqe_fcoe->index);
+               rc = lpfc_sli4_redisc_fcf_table(phba);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
+                                       LOG_DISCOVERY,
+                                       "2772 Issue FCF rediscover mabilbox "
+                                       "command failed, fail through to FCF "
+                                       "dead event\n");
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * Last resort will fail over by treating this
+                        * as a link down to FCF registration.
+                        */
+                       lpfc_sli4_fcf_dead_failthrough(phba);
+               } else
+                       /* Handling fast FCF failover to a DEAD FCF event
+                        * is considered equalivant to receiving CVL to all
+                        * vports.
+                        */
+                       lpfc_sli4_perform_all_vport_cvl(phba);
                break;
        case LPFC_FCOE_EVENT_TYPE_CVL:
-               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
                        "2718 Clear Virtual Link Received for VPI 0x%x"
                        " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
                vport = lpfc_find_vport_by_vpid(phba,
                                acqe_fcoe->index - phba->vpi_base);
-               if (!vport)
-                       break;
-               ndlp = lpfc_findnode_did(vport, Fabric_DID);
+               ndlp = lpfc_sli4_perform_vport_cvl(vport);
                if (!ndlp)
                        break;
-               shost = lpfc_shost_from_vport(vport);
-               if (phba->pport->port_state <= LPFC_FLOGI)
-                       break;
-               /* If virtual link is not yet instantiated ignore CVL */
-               if (vport->port_state <= LPFC_FDISC)
-                       break;
-
-               lpfc_linkdown_port(vport);
-               lpfc_cleanup_pending_mbox(vport);
-               spin_lock_irq(shost->host_lock);
-               vport->fc_flag |= FC_VPORT_CVL_RCVD;
-               spin_unlock_irq(shost->host_lock);
                active_vlink_present = 0;
 
                vports = lpfc_create_vport_work_array(phba);
@@ -3311,6 +3445,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                         * re-instantiate the Vlink using FDISC.
                         */
                        mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+                       shost = lpfc_shost_from_vport(vport);
                        spin_lock_irq(shost->host_lock);
                        ndlp->nlp_flag |= NLP_DELAY_TMO;
                        spin_unlock_irq(shost->host_lock);
@@ -3321,15 +3456,38 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                         * Otherwise, we request port to rediscover
                         * the entire FCF table for a fast recovery
                         * from possible case that the current FCF
-                        * is no longer valid.
+                        * is no longer valid if we are not already
+                        * in the FCF failover process.
                         */
+                       spin_lock_irq(&phba->hbalock);
+                       if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
+                               spin_unlock_irq(&phba->hbalock);
+                               break;
+                       }
+                       /* Mark the fast failover process in progress */
+                       phba->fcf.fcf_flag |= FCF_ACVL_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
+                                       LOG_DISCOVERY,
+                                       "2773 Start FCF fast failover due "
+                                       "to CVL event: evt_tag:x%x\n",
+                                       acqe_fcoe->event_tag);
                        rc = lpfc_sli4_redisc_fcf_table(phba);
-                       if (rc)
+                       if (rc) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
+                                               LOG_DISCOVERY,
+                                               "2774 Issue FCF rediscover "
+                                               "mabilbox command failed, "
+                                               "through to CVL event\n");
+                               spin_lock_irq(&phba->hbalock);
+                               phba->fcf.fcf_flag &= ~FCF_ACVL_DISC;
+                               spin_unlock_irq(&phba->hbalock);
                                /*
                                 * Last resort will be re-try on the
                                 * the current registered FCF entry.
                                 */
                                lpfc_retry_pport_discovery(phba);
+                       }
                }
                break;
        default:
@@ -3426,11 +3584,14 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
 
        /* Scan FCF table from the first entry to re-discover SAN */
-       rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+                       "2777 Start FCF table scan after FCF "
+                       "rediscovery quiescent period over\n");
+       rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
        if (rc)
-               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-                               "2747 Post FCF rediscovery read FCF record "
-                               "failed 0x%x\n", rc);
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
+                               "2747 Issue FCF scan read FCF mailbox "
+                               "command failed 0x%x\n", rc);
 }
 
 /**
@@ -3722,6 +3883,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        int rc, i, hbq_count, buf_size, dma_buf_size, max_buf_size;
        uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
        struct lpfc_mqe *mqe;
+       int longs;
 
        /* Before proceed, wait for POST done and device ready */
        rc = lpfc_sli4_post_status_check(phba);
@@ -3898,13 +4060,24 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                goto out_free_active_sgl;
        }
 
+       /* Allocate eligible FCF bmask memory for FCF round robin failover */
+       longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG;
+       phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long),
+                                        GFP_KERNEL);
+       if (!phba->fcf.fcf_rr_bmask) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2759 Failed allocate memory for FCF round "
+                               "robin failover bmask\n");
+               goto out_remove_rpi_hdrs;
+       }
+
        phba->sli4_hba.fcp_eq_hdl = kzalloc((sizeof(struct lpfc_fcp_eq_hdl) *
                                    phba->cfg_fcp_eq_count), GFP_KERNEL);
        if (!phba->sli4_hba.fcp_eq_hdl) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2572 Failed allocate memory for fast-path "
                                "per-EQ handle array\n");
-               goto out_remove_rpi_hdrs;
+               goto out_free_fcf_rr_bmask;
        }
 
        phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) *
@@ -3957,6 +4130,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 
 out_free_fcp_eq_hdl:
        kfree(phba->sli4_hba.fcp_eq_hdl);
+out_free_fcf_rr_bmask:
+       kfree(phba->fcf.fcf_rr_bmask);
 out_remove_rpi_hdrs:
        lpfc_sli4_remove_rpi_hdrs(phba);
 out_free_active_sgl:
@@ -4002,6 +4177,9 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        lpfc_sli4_remove_rpi_hdrs(phba);
        lpfc_sli4_remove_rpis(phba);
 
+       /* Free eligible FCF index bmask */
+       kfree(phba->fcf.fcf_rr_bmask);
+
        /* Free the ELS sgl list */
        lpfc_free_active_sgl(phba);
        lpfc_free_sgl_list(phba);
@@ -4397,6 +4575,7 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
 
                /* The list order is used by later block SGL registraton */
                spin_lock_irq(&phba->hbalock);
+               sglq_entry->state = SGL_FREED;
                list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list);
                phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry;
                phba->sli4_hba.total_sglq_bufs++;
index 954ba57..bb59e92 100644 (file)
@@ -35,6 +35,7 @@
 #define LOG_VPORT      0x00004000      /* NPIV events */
 #define LOF_SECURITY   0x00008000      /* Security events */
 #define LOG_EVENT      0x00010000      /* CT,TEMP,DUMP, logging */
+#define LOG_FIP                0x00020000      /* FIP events */
 #define LOG_ALL_MSG    0xffffffff      /* LOG all messages */
 
 #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
index 6c4dce1..1e61ae3 100644 (file)
@@ -1748,7 +1748,7 @@ lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
 }
 
 /**
- * lpfc_sli4_mbx_read_fcf_record - Allocate and construct read fcf mbox cmd
+ * lpfc_sli4_mbx_read_fcf_rec - Allocate and construct read fcf mbox cmd
  * @phba: pointer to lpfc hba data structure.
  * @fcf_index: index to fcf table.
  *
@@ -1759,9 +1759,9 @@ lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
  * NULL.
  **/
 int
-lpfc_sli4_mbx_read_fcf_record(struct lpfc_hba *phba,
-                             struct lpfcMboxq *mboxq,
-                             uint16_t fcf_index)
+lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba,
+                          struct lpfcMboxq *mboxq,
+                          uint16_t fcf_index)
 {
        void *virt_addr;
        dma_addr_t phys_addr;
index 483fb74..b16bb2c 100644 (file)
@@ -620,23 +620,40 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
        uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
        struct lpfc_scsi_buf *psb, *next_psb;
        unsigned long iflag = 0;
+       struct lpfc_iocbq *iocbq;
+       int i;
 
-       spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag);
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
        list_for_each_entry_safe(psb, next_psb,
                &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
                if (psb->cur_iocbq.sli4_xritag == xri) {
                        list_del(&psb->list);
                        psb->exch_busy = 0;
                        psb->status = IOSTAT_SUCCESS;
-                       spin_unlock_irqrestore(
-                               &phba->sli4_hba.abts_scsi_buf_list_lock,
-                               iflag);
+                       spin_unlock(
+                               &phba->sli4_hba.abts_scsi_buf_list_lock);
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
                        lpfc_release_scsi_buf_s4(phba, psb);
                        return;
                }
        }
-       spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
-                               iflag);
+       spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+       for (i = 1; i <= phba->sli.last_iotag; i++) {
+               iocbq = phba->sli.iocbq_lookup[i];
+
+               if (!(iocbq->iocb_flag &  LPFC_IO_FCP) ||
+                       (iocbq->iocb_flag & LPFC_IO_LIBDFC))
+                       continue;
+               if (iocbq->sli4_xritag != xri)
+                       continue;
+               psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
+               psb->exch_busy = 0;
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return;
+
+       }
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
 }
 
 /**
@@ -1006,6 +1023,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
        struct scatterlist *sgel = NULL;
        struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
        struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl;
+       struct lpfc_iocbq *iocbq = &lpfc_cmd->cur_iocbq;
        IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
        struct ulp_bde64 *data_bde = iocb_cmd->unsli3.fcp_ext.dbde;
        dma_addr_t physaddr;
@@ -1056,6 +1074,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
                        physaddr = sg_dma_address(sgel);
                        if (phba->sli_rev == 3 &&
                            !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
+                           !(iocbq->iocb_flag & DSS_SECURITY_OP) &&
                            nseg <= LPFC_EXT_DATA_BDE_COUNT) {
                                data_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
                                data_bde->tus.f.bdeSize = sg_dma_len(sgel);
@@ -1082,7 +1101,8 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
         * explicitly reinitialized since all iocb memory resources are reused.
         */
        if (phba->sli_rev == 3 &&
-           !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) {
+           !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
+           !(iocbq->iocb_flag & DSS_SECURITY_OP)) {
                if (num_bde > LPFC_EXT_DATA_BDE_COUNT) {
                        /*
                         * The extended IOCB format can only fit 3 BDE or a BPL.
@@ -1107,6 +1127,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
        } else {
                iocb_cmd->un.fcpi64.bdl.bdeSize =
                        ((num_bde + 2) * sizeof(struct ulp_bde64));
+               iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1);
        }
        fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
 
@@ -2079,8 +2100,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 
        if (resp_info & RSP_LEN_VALID) {
                rsplen = be32_to_cpu(fcprsp->rspRspLen);
-               if ((rsplen != 0 && rsplen != 4 && rsplen != 8) ||
-                   (fcprsp->rspInfo3 != RSP_NO_FAILURE)) {
+               if (rsplen != 0 && rsplen != 4 && rsplen != 8) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
                                 "2719 Invalid response length: "
                                 "tgt x%x lun x%x cmnd x%x rsplen x%x\n",
@@ -2090,6 +2110,17 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                        host_status = DID_ERROR;
                        goto out;
                }
+               if (fcprsp->rspInfo3 != RSP_NO_FAILURE) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+                                "2757 Protocol failure detected during "
+                                "processing of FCP I/O op: "
+                                "tgt x%x lun x%x cmnd x%x rspInfo3 x%x\n",
+                                cmnd->device->id,
+                                cmnd->device->lun, cmnd->cmnd[0],
+                                fcprsp->rspInfo3);
+                       host_status = DID_ERROR;
+                       goto out;
+               }
        }
 
        if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
index 35e3b96..fe6660c 100644 (file)
@@ -494,7 +494,7 @@ __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
  *
  * Returns sglq ponter = success, NULL = Failure.
  **/
-static struct lpfc_sglq *
+struct lpfc_sglq *
 __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
 {
        uint16_t adj_xri;
@@ -526,6 +526,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba)
                return NULL;
        adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
        phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+       sglq->state = SGL_ALLOCATED;
        return sglq;
 }
 
@@ -580,15 +581,18 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        else
                sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
        if (sglq)  {
-               if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) {
+               if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) &&
+                       (sglq->state != SGL_XRI_ABORTED)) {
                        spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
                                        iflag);
                        list_add(&sglq->list,
                                &phba->sli4_hba.lpfc_abts_els_sgl_list);
                        spin_unlock_irqrestore(
                                &phba->sli4_hba.abts_sgl_list_lock, iflag);
-               } else
+               } else {
+                       sglq->state = SGL_FREED;
                        list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+               }
        }
 
 
@@ -2258,41 +2262,56 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                        spin_unlock_irqrestore(&phba->hbalock,
                                                               iflag);
                                }
-                               if ((phba->sli_rev == LPFC_SLI_REV4) &&
-                                   (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) {
-                                       /* Set cmdiocb flag for the exchange
-                                        * busy so sgl (xri) will not be
-                                        * released until the abort xri is
-                                        * received from hba, clear the
-                                        * LPFC_DRIVER_ABORTED bit in case
-                                        * it was driver initiated abort.
-                                        */
-                                       spin_lock_irqsave(&phba->hbalock,
-                                                         iflag);
-                                       cmdiocbp->iocb_flag &=
-                                               ~LPFC_DRIVER_ABORTED;
-                                       cmdiocbp->iocb_flag |=
-                                               LPFC_EXCHANGE_BUSY;
-                                       spin_unlock_irqrestore(&phba->hbalock,
-                                                              iflag);
-                                       cmdiocbp->iocb.ulpStatus =
-                                               IOSTAT_LOCAL_REJECT;
-                                       cmdiocbp->iocb.un.ulpWord[4] =
-                                               IOERR_ABORT_REQUESTED;
-                                       /*
-                                        * For SLI4, irsiocb contains NO_XRI
-                                        * in sli_xritag, it shall not affect
-                                        * releasing sgl (xri) process.
-                                        */
-                                       saveq->iocb.ulpStatus =
-                                               IOSTAT_LOCAL_REJECT;
-                                       saveq->iocb.un.ulpWord[4] =
-                                               IOERR_SLI_ABORTED;
-                                       spin_lock_irqsave(&phba->hbalock,
-                                                         iflag);
-                                       saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
-                                       spin_unlock_irqrestore(&phba->hbalock,
-                                                              iflag);
+                               if (phba->sli_rev == LPFC_SLI_REV4) {
+                                       if (saveq->iocb_flag &
+                                           LPFC_EXCHANGE_BUSY) {
+                                               /* Set cmdiocb flag for the
+                                                * exchange busy so sgl (xri)
+                                                * will not be released until
+                                                * the abort xri is received
+                                                * from hba.
+                                                */
+                                               spin_lock_irqsave(
+                                                       &phba->hbalock, iflag);
+                                               cmdiocbp->iocb_flag |=
+                                                       LPFC_EXCHANGE_BUSY;
+                                               spin_unlock_irqrestore(
+                                                       &phba->hbalock, iflag);
+                                       }
+                                       if (cmdiocbp->iocb_flag &
+                                           LPFC_DRIVER_ABORTED) {
+                                               /*
+                                                * Clear LPFC_DRIVER_ABORTED
+                                                * bit in case it was driver
+                                                * initiated abort.
+                                                */
+                                               spin_lock_irqsave(
+                                                       &phba->hbalock, iflag);
+                                               cmdiocbp->iocb_flag &=
+                                                       ~LPFC_DRIVER_ABORTED;
+                                               spin_unlock_irqrestore(
+                                                       &phba->hbalock, iflag);
+                                               cmdiocbp->iocb.ulpStatus =
+                                                       IOSTAT_LOCAL_REJECT;
+                                               cmdiocbp->iocb.un.ulpWord[4] =
+                                                       IOERR_ABORT_REQUESTED;
+                                               /*
+                                                * For SLI4, irsiocb contains
+                                                * NO_XRI in sli_xritag, it
+                                                * shall not affect releasing
+                                                * sgl (xri) process.
+                                                */
+                                               saveq->iocb.ulpStatus =
+                                                       IOSTAT_LOCAL_REJECT;
+                                               saveq->iocb.un.ulpWord[4] =
+                                                       IOERR_SLI_ABORTED;
+                                               spin_lock_irqsave(
+                                                       &phba->hbalock, iflag);
+                                               saveq->iocb_flag |=
+                                                       LPFC_DELAY_MEM_FREE;
+                                               spin_unlock_irqrestore(
+                                                       &phba->hbalock, iflag);
+                                       }
                                }
                        }
                        (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -2515,14 +2534,16 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 
                        cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
                                                         &rspiocbq);
-                       if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
-                                       spin_unlock_irqrestore(&phba->hbalock,
-                                                              iflag);
-                                       (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
-                                                             &rspiocbq);
-                                       spin_lock_irqsave(&phba->hbalock,
-                                                         iflag);
-                               }
+                       if (unlikely(!cmdiocbq))
+                               break;
+                       if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED)
+                               cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+                       if (cmdiocbq->iocb_cmpl) {
+                               spin_unlock_irqrestore(&phba->hbalock, iflag);
+                               (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
+                                                     &rspiocbq);
+                               spin_lock_irqsave(&phba->hbalock, iflag);
+                       }
                        break;
                case LPFC_UNSOL_IOCB:
                        spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -3091,6 +3112,12 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask)
 
        /* Check to see if any errors occurred during init */
        if ((status & HS_FFERM) || (i >= 20)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2751 Adapter failed to restart, "
+                               "status reg x%x, FW Data: A8 x%x AC x%x\n",
+                               status,
+                               readl(phba->MBslimaddr + 0xa8),
+                               readl(phba->MBslimaddr + 0xac));
                phba->link_state = LPFC_HBA_ERROR;
                retval = 1;
        }
@@ -3278,6 +3305,9 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
        if (retval != MBX_SUCCESS) {
                if (retval != MBX_BUSY)
                        mempool_free(pmb, phba->mbox_mem_pool);
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2752 KILL_BOARD command failed retval %d\n",
+                               retval);
                spin_lock_irq(&phba->hbalock);
                phba->link_flag &= ~LS_IGNORE_ERATT;
                spin_unlock_irq(&phba->hbalock);
@@ -4035,7 +4065,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 
 lpfc_sli_hba_setup_error:
        phba->link_state = LPFC_HBA_ERROR;
-       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "0445 Firmware initialization failed\n");
        return rc;
 }
@@ -4388,7 +4418,13 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
 
        /* Read the port's service parameters. */
-       lpfc_read_sparam(phba, mboxq, vport->vpi);
+       rc = lpfc_read_sparam(phba, mboxq, vport->vpi);
+       if (rc) {
+               phba->link_state = LPFC_HBA_ERROR;
+               rc = -ENOMEM;
+               goto out_free_vpd;
+       }
+
        mboxq->vport = vport;
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
        mp = (struct lpfc_dmabuf *) mboxq->context1;
@@ -4483,6 +4519,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        /* Post receive buffers to the device */
        lpfc_sli4_rb_setup(phba);
 
+       /* Reset HBA FCF states after HBA reset */
+       phba->fcf.fcf_flag = 0;
+       phba->fcf.current_rec.flag = 0;
+
        /* Start the ELS watchdog timer */
        mod_timer(&vport->els_tmofunc,
                  jiffies + HZ * (phba->fc_ratov * 2));
@@ -7436,6 +7476,7 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
 {
        wait_queue_head_t *pdone_q;
        unsigned long iflags;
+       struct lpfc_scsi_buf *lpfc_cmd;
 
        spin_lock_irqsave(&phba->hbalock, iflags);
        cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
@@ -7443,6 +7484,14 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
                memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
                       &rspiocbq->iocb, sizeof(IOCB_t));
 
+       /* Set the exchange busy flag for task management commands */
+       if ((cmdiocbq->iocb_flag & LPFC_IO_FCP) &&
+               !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) {
+               lpfc_cmd = container_of(cmdiocbq, struct lpfc_scsi_buf,
+                       cur_iocbq);
+               lpfc_cmd->exch_busy = rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY;
+       }
+
        pdone_q = cmdiocbq->context_un.wait_queue;
        if (pdone_q)
                wake_up(pdone_q);
@@ -9061,6 +9110,12 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
        /* Fake the irspiocb and copy necessary response information */
        lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe);
 
+       if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) {
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+       }
+
        /* Pass the cmd_iocb and the rsp state to the upper layer */
        (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
 }
@@ -11941,15 +11996,19 @@ lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_sli4_read_fcf_record - Read the driver's default FCF Record.
+ * lpfc_sli4_fcf_scan_read_fcf_rec - Read hba fcf record for fcf scan.
  * @phba: pointer to lpfc hba data structure.
  * @fcf_index: FCF table entry offset.
  *
- * This routine is invoked to read up to @fcf_num of FCF record from the
- * device starting with the given @fcf_index.
+ * This routine is invoked to scan the entire FCF table by reading FCF
+ * record and processing it one at a time starting from the @fcf_index
+ * for initial FCF discovery or fast FCF failover rediscovery.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
  **/
 int
-lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
+lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
 {
        int rc = 0, error;
        LPFC_MBOXQ_t *mboxq;
@@ -11961,17 +12020,17 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
                                "2000 Failed to allocate mbox for "
                                "READ_FCF cmd\n");
                error = -ENOMEM;
-               goto fail_fcfscan;
+               goto fail_fcf_scan;
        }
        /* Construct the read FCF record mailbox command */
-       rc = lpfc_sli4_mbx_read_fcf_record(phba, mboxq, fcf_index);
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
        if (rc) {
                error = -EINVAL;
-               goto fail_fcfscan;
+               goto fail_fcf_scan;
        }
        /* Issue the mailbox command asynchronously */
        mboxq->vport = phba->pport;
-       mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec;
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED)
                error = -EIO;
@@ -11979,9 +12038,13 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
                spin_lock_irq(&phba->hbalock);
                phba->hba_flag |= FCF_DISC_INPROGRESS;
                spin_unlock_irq(&phba->hbalock);
+               /* Reset FCF round robin index bmask for new scan */
+               if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
+                       memset(phba->fcf.fcf_rr_bmask, 0,
+                              sizeof(*phba->fcf.fcf_rr_bmask));
                error = 0;
        }
-fail_fcfscan:
+fail_fcf_scan:
        if (error) {
                if (mboxq)
                        lpfc_sli4_mbox_cmd_free(phba, mboxq);
@@ -11994,6 +12057,181 @@ fail_fcfscan:
 }
 
 /**
+ * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for round robin fcf.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read an FCF record indicated by @fcf_index
+ * and to use it for FLOGI round robin FCF failover.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
+ **/
+int
+lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       int rc = 0, error;
+       LPFC_MBOXQ_t *mboxq;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
+                               "2763 Failed to allocate mbox for "
+                               "READ_FCF cmd\n");
+               error = -ENOMEM;
+               goto fail_fcf_read;
+       }
+       /* Construct the read FCF record mailbox command */
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
+       if (rc) {
+               error = -EINVAL;
+               goto fail_fcf_read;
+       }
+       /* Issue the mailbox command asynchronously */
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_rr_read_fcf_rec;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED)
+               error = -EIO;
+       else
+               error = 0;
+
+fail_fcf_read:
+       if (error && mboxq)
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       return error;
+}
+
+/**
+ * lpfc_sli4_read_fcf_rec - Read hba fcf record for update eligible fcf bmask.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read an FCF record indicated by @fcf_index to
+ * determine whether it's eligible for FLOGI round robin failover list.
+ *
+ * Return 0 if the mailbox command is submitted sucessfully, none 0
+ * otherwise.
+ **/
+int
+lpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       int rc = 0, error;
+       LPFC_MBOXQ_t *mboxq;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT,
+                               "2758 Failed to allocate mbox for "
+                               "READ_FCF cmd\n");
+                               error = -ENOMEM;
+                               goto fail_fcf_read;
+       }
+       /* Construct the read FCF record mailbox command */
+       rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index);
+       if (rc) {
+               error = -EINVAL;
+               goto fail_fcf_read;
+       }
+       /* Issue the mailbox command asynchronously */
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_rec;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED)
+               error = -EIO;
+       else
+               error = 0;
+
+fail_fcf_read:
+       if (error && mboxq)
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       return error;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to get the next eligible FCF record index in a round
+ * robin fashion. If the next eligible FCF record index equals to the
+ * initial round robin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
+ * shall be returned, otherwise, the next eligible FCF record's index
+ * shall be returned.
+ **/
+uint16_t
+lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
+{
+       uint16_t next_fcf_index;
+
+       /* Search from the currently registered FCF index */
+       next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
+                                      LPFC_SLI4_FCF_TBL_INDX_MAX,
+                                      phba->fcf.current_rec.fcf_indx);
+       /* Wrap around condition on phba->fcf.fcf_rr_bmask */
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+               next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
+                                              LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
+       /* Round robin failover stop condition */
+       if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
+               return LPFC_FCOE_FCF_NEXT_NONE;
+
+       return next_fcf_index;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_index_set - Set bmask with eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine sets the FCF record index in to the eligible bmask for
+ * round robin failover search. It checks to make sure that the index
+ * does not go beyond the range of the driver allocated bmask dimension
+ * before setting the bit.
+ *
+ * Returns 0 if the index bit successfully set, otherwise, it returns
+ * -EINVAL.
+ **/
+int
+lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                               "2610 HBA FCF index reached driver's "
+                               "book keeping dimension: fcf_index:%d, "
+                               "driver_bmask_max:%d\n",
+                               fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
+               return -EINVAL;
+       }
+       /* Set the eligible FCF record index bmask */
+       set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+
+       return 0;
+}
+
+/**
+ * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine clears the FCF record index from the eligible bmask for
+ * round robin failover search. It checks to make sure that the index
+ * does not go beyond the range of the driver allocated bmask dimension
+ * before clearing the bit.
+ **/
+void
+lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                               "2762 HBA FCF index goes beyond driver's "
+                               "book keeping dimension: fcf_index:%d, "
+                               "driver_bmask_max:%d\n",
+                               fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
+               return;
+       }
+       /* Clear the eligible FCF record index bmask */
+       clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+}
+
+/**
  * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table
  * @phba: pointer to lpfc hba data structure.
  *
@@ -12014,21 +12252,40 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
        shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
                             &redisc_fcf->header.cfg_shdr.response);
        if (shdr_status || shdr_add_status) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2746 Requesting for FCF rediscovery failed "
                                "status x%x add_status x%x\n",
                                shdr_status, shdr_add_status);
-               /*
-                * Request failed, last resort to re-try current
-                * registered FCF entry
-                */
-               lpfc_retry_pport_discovery(phba);
-       } else
+               if (phba->fcf.fcf_flag & FCF_ACVL_DISC) {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_ACVL_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * CVL event triggered FCF rediscover request failed,
+                        * last resort to re-try current registered FCF entry.
+                        */
+                       lpfc_retry_pport_discovery(phba);
+               } else {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+                       spin_unlock_irq(&phba->hbalock);
+                       /*
+                        * DEAD FCF event triggered FCF rediscover request
+                        * failed, last resort to fail over as a link down
+                        * to FCF registration.
+                        */
+                       lpfc_sli4_fcf_dead_failthrough(phba);
+               }
+       } else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2775 Start FCF rediscovery quiescent period "
+                               "wait timer before scaning FCF table\n");
                /*
                 * Start FCF rediscovery wait timer for pending FCF
                 * before rescan FCF record table.
                 */
                lpfc_fcf_redisc_wait_start_timer(phba);
+       }
 
        mempool_free(mbox, phba->mbox_mem_pool);
 }
@@ -12047,6 +12304,9 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
        struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
        int rc, length;
 
+       /* Cancel retry delay timers to all vports before FCF rediscover */
+       lpfc_cancel_all_vport_retry_delay_timer(phba);
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -12078,6 +12338,31 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
 }
 
 /**
+ * lpfc_sli4_fcf_dead_failthrough - Failthrough routine to fcf dead event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function is the failover routine as a last resort to the FCF DEAD
+ * event when driver failed to perform fast FCF failover.
+ **/
+void
+lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba)
+{
+       uint32_t link_state;
+
+       /*
+        * Last resort as FCF DEAD event failover will treat this as
+        * a link down, but save the link state because we don't want
+        * it to be changed to Link Down unless it is already down.
+        */
+       link_state = phba->link_state;
+       lpfc_linkdown(phba);
+       phba->link_state = link_state;
+
+       /* Unregister FCF if no devices connected to it */
+       lpfc_unregister_unused_fcf(phba);
+}
+
+/**
  * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
  * @phba: pointer to lpfc hba data structure.
  *
index dfcf543..b4a639c 100644 (file)
@@ -62,6 +62,7 @@ struct lpfc_iocbq {
 #define LPFC_DELAY_MEM_FREE    0x20    /* Defer free'ing of FC data */
 #define LPFC_EXCHANGE_BUSY     0x40    /* SLI4 hba reported XB in response */
 #define LPFC_USE_FCPWQIDX      0x80    /* Submit to specified FCPWQ index */
+#define DSS_SECURITY_OP                0x100   /* security IO */
 
 #define LPFC_FIP_ELS_ID_MASK   0xc000  /* ELS_ID range 0-3, non-shifted mask */
 #define LPFC_FIP_ELS_ID_SHIFT  14
index 8630883..4a35e7b 100644 (file)
@@ -153,15 +153,27 @@ struct lpfc_fcf {
 #define FCF_REGISTERED 0x02 /* FCF registered with FW */
 #define FCF_SCAN_DONE  0x04 /* FCF table scan done */
 #define FCF_IN_USE     0x08 /* Atleast one discovery completed */
-#define FCF_REDISC_PEND        0x10 /* FCF rediscovery pending */
-#define FCF_REDISC_EVT 0x20 /* FCF rediscovery event to worker thread */
-#define FCF_REDISC_FOV 0x40 /* Post FCF rediscovery fast failover */
+#define FCF_INIT_DISC  0x10 /* Initial FCF discovery */
+#define FCF_DEAD_DISC  0x20 /* FCF DEAD fast FCF failover discovery */
+#define FCF_ACVL_DISC  0x40 /* All CVL fast FCF failover discovery */
+#define FCF_DISCOVERY  (FCF_INIT_DISC | FCF_DEAD_DISC | FCF_ACVL_DISC)
+#define FCF_REDISC_PEND        0x80 /* FCF rediscovery pending */
+#define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */
+#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
        uint32_t addr_mode;
+       uint16_t fcf_rr_init_indx;
        struct lpfc_fcf_rec current_rec;
        struct lpfc_fcf_rec failover_rec;
        struct timer_list redisc_wait;
+       unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */
 };
 
+/*
+ * Maximum FCF table index, it is for driver internal book keeping, it
+ * just needs to be no less than the supported HBA's FCF table size.
+ */
+#define LPFC_SLI4_FCF_TBL_INDX_MAX     32
+
 #define LPFC_REGION23_SIGNATURE "RG23"
 #define LPFC_REGION23_VERSION  1
 #define LPFC_REGION23_LAST_REC  0xff
@@ -431,11 +443,18 @@ enum lpfc_sge_type {
        SCSI_BUFF_TYPE
 };
 
+enum lpfc_sgl_state {
+       SGL_FREED,
+       SGL_ALLOCATED,
+       SGL_XRI_ABORTED
+};
+
 struct lpfc_sglq {
        /* lpfc_sglqs are used in double linked lists */
        struct list_head list;
        struct list_head clist;
        enum lpfc_sge_type buff_type; /* is this a scsi sgl */
+       enum lpfc_sgl_state state;
        uint16_t iotag;         /* pre-assigned IO tag */
        uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
        struct sli4_sge *sgl;   /* pre-assigned SGL */
@@ -463,8 +482,8 @@ void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *);
 void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t);
 void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t,
                           struct lpfc_mbx_sge *);
-int lpfc_sli4_mbx_read_fcf_record(struct lpfc_hba *, struct lpfcMboxq *,
-                                 uint16_t);
+int lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *, struct lpfcMboxq *,
+                              uint16_t);
 
 void lpfc_sli4_hba_reset(struct lpfc_hba *);
 struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
@@ -523,8 +542,13 @@ int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t);
 uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
 uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
 void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
-int lpfc_sli4_read_fcf_record(struct lpfc_hba *, uint16_t);
-void lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_read_fcf_rec(struct lpfc_hba *, uint16_t);
+void lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli4_unregister_fcf(struct lpfc_hba *);
 int lpfc_sli4_post_status_check(struct lpfc_hba *);
 uint8_t lpfc_sli4_mbox_opcode_get(struct lpfc_hba *, struct lpfcMboxq *);
 
index ac276aa..013deec 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.9"
+#define LPFC_DRIVER_VERSION "8.3.10"
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME    "lpfc:fp"
index dc86e87..869f76c 100644 (file)
@@ -123,7 +123,12 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
        }
        mb = &pmb->u.mb;
 
-       lpfc_read_sparam(phba, pmb, vport->vpi);
+       rc = lpfc_read_sparam(phba, pmb, vport->vpi);
+       if (rc) {
+               mempool_free(pmb, phba->mbox_mem_pool);
+               return -ENOMEM;
+       }
+
        /*
         * Grab buffer pointer and clear context1 so we can use
         * lpfc_sli_issue_box_wait
index 2422347..60de850 100644 (file)
@@ -1433,6 +1433,10 @@ int osd_finalize_request(struct osd_request *or,
        cdbh->command_specific_options |= or->attributes_mode;
        if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
                ret = _osd_req_finalize_attr_page(or);
+               if (ret) {
+                       OSD_DEBUG("_osd_req_finalize_attr_page failed\n");
+                       return ret;
+               }
        } else {
                /* TODO: I think that for the GET_ATTR command these 2 should
                 * be reversed to keep them in execution order (for embeded
index c2341af..0212464 100644 (file)
@@ -1717,6 +1717,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
        cfg_mem->data = data;
 
        ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem);
+       if (ret)
                goto cs_failed;
 
        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
index bd88349..2c146b4 100644 (file)
@@ -63,6 +63,7 @@ static int raid_match(struct attribute_container *cont, struct device *dev)
         * emulated RAID devices, so start with SCSI */
        struct raid_internal *i = ac_to_raid_internal(cont);
 
+#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE)
        if (scsi_is_sdev_device(dev)) {
                struct scsi_device *sdev = to_scsi_device(dev);
 
@@ -71,6 +72,7 @@ static int raid_match(struct attribute_container *cont, struct device *dev)
 
                return i->f->is_raid(dev);
        }
+#endif
        /* FIXME: look at other subsystems too */
        return 0;
 }
index 79660ee..1d5b721 100644 (file)
@@ -1232,6 +1232,15 @@ store_fc_vport_delete(struct device *dev, struct device_attribute *attr,
 {
        struct fc_vport *vport = transport_class_to_vport(dev);
        struct Scsi_Host *shost = vport_to_shost(vport);
+       unsigned long flags;
+
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) {
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               return -EBUSY;
+       }
+       vport->flags |= FC_VPORT_DELETING;
+       spin_unlock_irqrestore(shost->host_lock, flags);
 
        fc_queue_work(shost, &vport->vport_delete_work);
        return count;
@@ -1821,6 +1830,9 @@ store_fc_host_vport_delete(struct device *dev, struct device_attribute *attr,
        list_for_each_entry(vport, &fc_host->vports, peers) {
                if ((vport->channel == 0) &&
                    (vport->port_name == wwpn) && (vport->node_name == wwnn)) {
+                       if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))
+                               break;
+                       vport->flags |= FC_VPORT_DELETING;
                        match = 1;
                        break;
                }
@@ -3370,18 +3382,6 @@ fc_vport_terminate(struct fc_vport *vport)
        unsigned long flags;
        int stat;
 
-       spin_lock_irqsave(shost->host_lock, flags);
-       if (vport->flags & FC_VPORT_CREATING) {
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               return -EBUSY;
-       }
-       if (vport->flags & (FC_VPORT_DEL)) {
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               return -EALREADY;
-       }
-       vport->flags |= FC_VPORT_DELETING;
-       spin_unlock_irqrestore(shost->host_lock, flags);
-
        if (i->f->vport_delete)
                stat = i->f->vport_delete(vport);
        else
index 83881df..7b75c8a 100644 (file)
@@ -1948,7 +1948,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
 {
        struct request_queue *q = sdkp->disk->queue;
        unsigned int sector_sz = sdkp->device->sector_size;
-       const int vpd_len = 32;
+       const int vpd_len = 64;
        unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
 
        if (!buffer ||
@@ -1998,7 +1998,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
 {
        unsigned char *buffer;
        u16 rot;
-       const int vpd_len = 32;
+       const int vpd_len = 64;
 
        buffer = kmalloc(vpd_len, GFP_KERNEL);
 
index d514e28..d2e0321 100644 (file)
@@ -474,7 +474,7 @@ static void sunsab_stop_rx(struct uart_port *port)
 {
        struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 
-       up->interrupt_mask0 |= SAB82532_ISR0_TCD;
+       up->interrupt_mask0 |= SAB82532_IMR0_TCD;
        writeb(up->interrupt_mask1, &up->regs->w.imr0);
 }
 
index ab2ab3c..f0a6c61 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <asm/io.h>
-#if defined(CONFIG_OF)
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
@@ -581,7 +581,7 @@ static struct platform_driver ulite_platform_driver = {
 /* ---------------------------------------------------------------------
  * OF bus bindings
  */
-#if defined(CONFIG_OF)
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
 static int __devinit
 ulite_of_probe(struct of_device *op, const struct of_device_id *match)
 {
@@ -631,11 +631,11 @@ static inline void __exit ulite_of_unregister(void)
 {
        of_unregister_platform_driver(&ulite_of_driver);
 }
-#else /* CONFIG_OF */
-/* CONFIG_OF not enabled; do nothing helpers */
+#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
+/* Appropriate config not enabled; do nothing helpers */
 static inline int __init ulite_of_register(void) { return 0; }
 static inline void __exit ulite_of_unregister(void) { }
-#endif /* CONFIG_OF */
+#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
 
 /* ---------------------------------------------------------------------
  * Module setup/teardown
index 715c518..4dd786b 100644 (file)
@@ -578,6 +578,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
        struct spi_master *spi_cntrl;
        u32 l = 0, div = 0;
        u8 word_len = spi->bits_per_word;
+       u32 speed_hz = spi->max_speed_hz;
 
        mcspi = spi_master_get_devdata(spi->master);
        spi_cntrl = mcspi->master;
@@ -587,9 +588,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 
        cs->word_len = word_len;
 
-       if (spi->max_speed_hz) {
+       if (t && t->speed_hz)
+               speed_hz = t->speed_hz;
+
+       if (speed_hz) {
                while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div))
-                                       > spi->max_speed_hz)
+                                       > speed_hz)
                        div++;
        } else
                div = 15;
@@ -751,11 +755,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
-       /* Unlink controller state from context save list */
-       cs = spi->controller_state;
-       list_del(&cs->node);
+       if (spi->controller_state) {
+               /* Unlink controller state from context save list */
+               cs = spi->controller_state;
+               list_del(&cs->node);
 
-       kfree(spi->controller_state);
+               kfree(spi->controller_state);
+       }
 
        if (mcspi_dma->dma_rx_channel != -1) {
                omap_free_dma(mcspi_dma->dma_rx_channel);
index dd7ea4c..eb44b60 100644 (file)
@@ -394,6 +394,7 @@ MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
 
 static int __init samsung_init(void)
 {
+       struct backlight_properties props;
        struct sabi_retval sretval;
        const char *testStr = "SECLINUX";
        void __iomem *memcheck;
@@ -486,12 +487,14 @@ static int __init samsung_init(void)
                goto error_no_platform;
 
        /* create a backlight device to talk to this one */
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = MAX_BRIGHT;
        backlight_device = backlight_device_register("samsung", &sdev->dev,
-                                                    NULL, &backlight_ops);
+                                                    NULL, &backlight_ops,
+                                                    &props);
        if (IS_ERR(backlight_device))
                goto error_no_backlight;
 
-       backlight_device->props.max_brightness = MAX_BRIGHT;
        backlight_device->props.brightness = read_brightness();
        backlight_device->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(backlight_device);
index 4d2952f..3adab04 100644 (file)
@@ -202,6 +202,7 @@ static void appledisplay_work(struct work_struct *work)
 static int appledisplay_probe(struct usb_interface *iface,
        const struct usb_device_id *id)
 {
+       struct backlight_properties props;
        struct appledisplay *pdata;
        struct usb_device *udev = interface_to_usbdev(iface);
        struct usb_host_interface *iface_desc;
@@ -279,16 +280,16 @@ static int appledisplay_probe(struct usb_interface *iface,
        /* Register backlight device */
        snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
                atomic_inc_return(&count_displays) - 1);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 0xff;
        pdata->bd = backlight_device_register(bl_name, NULL, pdata,
-                                               &appledisplay_bl_data);
+                                             &appledisplay_bl_data, &props);
        if (IS_ERR(pdata->bd)) {
                dev_err(&iface->dev, "Backlight registration failed\n");
                retval = PTR_ERR(pdata->bd);
                goto error;
        }
 
-       pdata->bd->props.max_brightness = 0xff;
-
        /* Try to get brightness */
        brightness = appledisplay_bl_get_brightness(pdata->bd);
 
index dabe804..6e16244 100644 (file)
@@ -914,7 +914,7 @@ config FB_XVR2500
 
 config FB_XVR1000
        bool "Sun XVR-1000 support"
-       depends on SPARC64
+       depends on (FB = y) && SPARC64
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -1881,7 +1881,7 @@ config FB_W100
 
 config FB_SH_MOBILE_LCDC
        tristate "SuperH Mobile LCDC framebuffer support"
-       depends on FB && SUPERH && HAVE_CLK
+       depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index a21efcd..afe21e6 100644 (file)
@@ -65,16 +65,16 @@ static void clcdfb_disable(struct clcd_fb *fb)
        if (fb->board->disable)
                fb->board->disable(fb);
 
-       val = readl(fb->regs + CLCD_CNTL);
+       val = readl(fb->regs + fb->off_cntl);
        if (val & CNTL_LCDPWR) {
                val &= ~CNTL_LCDPWR;
-               writel(val, fb->regs + CLCD_CNTL);
+               writel(val, fb->regs + fb->off_cntl);
 
                clcdfb_sleep(20);
        }
        if (val & CNTL_LCDEN) {
                val &= ~CNTL_LCDEN;
-               writel(val, fb->regs + CLCD_CNTL);
+               writel(val, fb->regs + fb->off_cntl);
        }
 
        /*
@@ -94,7 +94,7 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
         * Bring up by first enabling..
         */
        cntl |= CNTL_LCDEN;
-       writel(cntl, fb->regs + CLCD_CNTL);
+       writel(cntl, fb->regs + fb->off_cntl);
 
        clcdfb_sleep(20);
 
@@ -102,7 +102,7 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
         * and now apply power.
         */
        cntl |= CNTL_LCDPWR;
-       writel(cntl, fb->regs + CLCD_CNTL);
+       writel(cntl, fb->regs + fb->off_cntl);
 
        /*
         * finally, enable the interface.
@@ -233,7 +233,7 @@ static int clcdfb_set_par(struct fb_info *info)
                readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
                readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
                readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
-               readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL));
+               readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
 #endif
 
        return 0;
@@ -345,6 +345,23 @@ static int clcdfb_register(struct clcd_fb *fb)
 {
        int ret;
 
+       /*
+        * ARM PL111 always has IENB at 0x1c; it's only PL110
+        * which is reversed on some platforms.
+        */
+       if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
+               fb->off_ienb = CLCD_PL111_IENB;
+               fb->off_cntl = CLCD_PL111_CNTL;
+       } else {
+#ifdef CONFIG_ARCH_VERSATILE
+               fb->off_ienb = CLCD_PL111_IENB;
+               fb->off_cntl = CLCD_PL111_CNTL;
+#else
+               fb->off_ienb = CLCD_PL110_IENB;
+               fb->off_cntl = CLCD_PL110_CNTL;
+#endif
+       }
+
        fb->clk = clk_get(&fb->dev->dev, NULL);
        if (IS_ERR(fb->clk)) {
                ret = PTR_ERR(fb->clk);
@@ -416,7 +433,7 @@ static int clcdfb_register(struct clcd_fb *fb)
        /*
         * Ensure interrupts are disabled.
         */
-       writel(0, fb->regs + CLCD_IENB);
+       writel(0, fb->regs + fb->off_ienb);
 
        fb_set_var(&fb->fb, &fb->fb.var);
 
index 3d886c6..11de3bf 100644 (file)
@@ -117,6 +117,7 @@ static struct backlight_ops atmel_lcdc_bl_ops = {
 
 static void init_backlight(struct atmel_lcdfb_info *sinfo)
 {
+       struct backlight_properties props;
        struct backlight_device *bl;
 
        sinfo->bl_power = FB_BLANK_UNBLANK;
@@ -124,8 +125,10 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
        if (sinfo->backlight)
                return;
 
-       bl = backlight_device_register("backlight", &sinfo->pdev->dev,
-                       sinfo, &atmel_lcdc_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 0xff;
+       bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+                                      &atmel_lcdc_bl_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
                                PTR_ERR(bl));
@@ -135,7 +138,6 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
 
        bl->props.power = FB_BLANK_UNBLANK;
        bl->props.fb_blank = FB_BLANK_UNBLANK;
-       bl->props.max_brightness = 0xff;
        bl->props.brightness = atmel_bl_get_brightness(bl);
 }
 
index 9ee67d6..a489be0 100644 (file)
@@ -1802,6 +1802,7 @@ static void aty128_bl_set_power(struct fb_info *info, int power)
 
 static void aty128_bl_init(struct aty128fb_par *par)
 {
+       struct backlight_properties props;
        struct fb_info *info = pci_get_drvdata(par->pdev);
        struct backlight_device *bd;
        char name[12];
@@ -1817,7 +1818,10 @@ static void aty128_bl_init(struct aty128fb_par *par)
 
        snprintf(name, sizeof(name), "aty128bl%d", info->node);
 
-       bd = backlight_device_register(name, info->dev, par, &aty128_bl_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, info->dev, par, &aty128_bl_data,
+                                      &props);
        if (IS_ERR(bd)) {
                info->bl_dev = NULL;
                printk(KERN_WARNING "aty128: Backlight registration failed\n");
@@ -1829,7 +1833,6 @@ static void aty128_bl_init(struct aty128fb_par *par)
                 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
                219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
 
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd->props.brightness = bd->props.max_brightness;
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index e45ab8d..29d7285 100644 (file)
@@ -2232,6 +2232,7 @@ static struct backlight_ops aty_bl_data = {
 
 static void aty_bl_init(struct atyfb_par *par)
 {
+       struct backlight_properties props;
        struct fb_info *info = pci_get_drvdata(par->pdev);
        struct backlight_device *bd;
        char name[12];
@@ -2243,7 +2244,10 @@ static void aty_bl_init(struct atyfb_par *par)
 
        snprintf(name, sizeof(name), "atybl%d", info->node);
 
-       bd = backlight_device_register(name, info->dev, par, &aty_bl_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, info->dev, par, &aty_bl_data,
+                                      &props);
        if (IS_ERR(bd)) {
                info->bl_dev = NULL;
                printk(KERN_WARNING "aty: Backlight registration failed\n");
@@ -2255,7 +2259,6 @@ static void aty_bl_init(struct atyfb_par *par)
                            0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
                            0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
 
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd->props.brightness = bd->props.max_brightness;
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index fa1198c..9fc8c66 100644 (file)
@@ -134,6 +134,7 @@ static struct backlight_ops radeon_bl_data = {
 
 void radeonfb_bl_init(struct radeonfb_info *rinfo)
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
        struct radeon_bl_privdata *pdata;
        char name[12];
@@ -155,7 +156,10 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
 
        snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
 
-       bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, rinfo->info->dev, pdata,
+                                      &radeon_bl_data, &props);
        if (IS_ERR(bd)) {
                rinfo->info->bl_dev = NULL;
                printk("radeonfb: Backlight registration failed\n");
@@ -185,7 +189,6 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
                 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
                217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
 
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd->props.brightness = bd->props.max_brightness;
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index b8f705c..93e25c7 100644 (file)
@@ -187,6 +187,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        struct pm860x_backlight_data *data;
        struct backlight_device *bl;
        struct resource *res;
+       struct backlight_properties props;
        unsigned char value;
        char name[MFD_NAME_SIZE];
        int ret;
@@ -223,14 +224,15 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = MAX_BRIGHTNESS;
        bl = backlight_device_register(name, &pdev->dev, data,
-                                       &pm860x_backlight_ops);
+                                       &pm860x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                kfree(data);
                return PTR_ERR(bl);
        }
-       bl->props.max_brightness = MAX_BRIGHTNESS;
        bl->props.brightness = MAX_BRIGHTNESS;
 
        platform_set_drvdata(pdev, bl);
index 0c77fc6..c025c84 100644 (file)
@@ -31,6 +31,13 @@ config LCD_CORGI
          Say y here to support the LCD panels usually found on SHARP
          corgi (C7x0) and spitz (Cxx00) models.
 
+config LCD_L4F00242T03
+       tristate "Epson L4F00242T03 LCD"
+       depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+       help
+         SPI driver for Epson L4F00242T03. This provides basic support
+         for init and powering the LCD up/down through a sysfs interface.
+
 config LCD_LMS283GF05
        tristate "Samsung LMS283GF05 LCD"
        depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
index 6c704d4..09d1f14 100644 (file)
@@ -3,6 +3,7 @@
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
 obj-$(CONFIG_LCD_CORGI)                   += corgi_lcd.o
 obj-$(CONFIG_LCD_HP700)                   += jornada720_lcd.o
+obj-$(CONFIG_LCD_L4F00242T03)     += l4f00242t03.o
 obj-$(CONFIG_LCD_LMS283GF05)      += lms283gf05.o
 obj-$(CONFIG_LCD_LTV350QV)        += ltv350qv.o
 obj-$(CONFIG_LCD_ILI9320)         += ili9320.o
index 86d95c2..5183f0e 100644 (file)
@@ -278,6 +278,7 @@ static const struct attribute_group adp5520_bl_attr_group = {
 
 static int __devinit adp5520_bl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct backlight_device *bl;
        struct adp5520_bl *data;
        int ret = 0;
@@ -300,17 +301,17 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
 
        mutex_init(&data->lock);
 
-       bl = backlight_device_register(pdev->name, data->master,
-                       data, &adp5520_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = ADP5020_MAX_BRIGHTNESS;
+       bl = backlight_device_register(pdev->name, data->master, data,
+                                      &adp5520_bl_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                kfree(data);
                return PTR_ERR(bl);
        }
 
-       bl->props.max_brightness =
-               bl->props.brightness = ADP5020_MAX_BRIGHTNESS;
-
+       bl->props.brightness = ADP5020_MAX_BRIGHTNESS;
        if (data->pdata->en_ambl_sens)
                ret = sysfs_create_group(&bl->dev.kobj,
                        &adp5520_bl_attr_group);
index d769b0b..b0624b9 100644 (file)
@@ -56,7 +56,7 @@ static int adx_backlight_get_brightness(struct backlight_device *bldev)
        return brightness & 0xff;
 }
 
-static int adx_backlight_check_fb(struct fb_info *fb)
+static int adx_backlight_check_fb(struct backlight_device *bldev, struct fb_info *fb)
 {
        return 1;
 }
@@ -70,6 +70,7 @@ static const struct backlight_ops adx_backlight_ops = {
 
 static int __devinit adx_backlight_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct backlight_device *bldev;
        struct resource *res;
        struct adxbl *bl;
@@ -101,14 +102,15 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
                goto out;
        }
 
-       bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl,
-                       &adx_backlight_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 0xff;
+       bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
+                                         bl, &adx_backlight_ops, &props);
        if (!bldev) {
                ret = -ENOMEM;
                goto out;
        }
 
-       bldev->props.max_brightness = 0xff;
        bldev->props.brightness = 0xff;
        bldev->props.power = FB_BLANK_UNBLANK;
 
index f625ffc..2d97605 100644 (file)
@@ -120,6 +120,7 @@ static const struct backlight_ops atmel_pwm_bl_ops = {
 
 static int atmel_pwm_bl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        const struct atmel_pwm_bl_platform_data *pdata;
        struct backlight_device *bldev;
        struct atmel_pwm_bl *pwmbl;
@@ -165,8 +166,10 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
                        goto err_free_gpio;
        }
 
-       bldev = backlight_device_register("atmel-pwm-bl",
-                       &pdev->dev, pwmbl, &atmel_pwm_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
+       bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl,
+                                         &atmel_pwm_bl_ops, &props);
        if (IS_ERR(bldev)) {
                retval = PTR_ERR(bldev);
                goto err_free_gpio;
@@ -178,7 +181,6 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 
        /* Power up the backlight by default at middle intesity. */
        bldev->props.power = FB_BLANK_UNBLANK;
-       bldev->props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
        bldev->props.brightness = bldev->props.max_brightness / 2;
 
        retval = atmel_pwm_bl_init_pwm(pwmbl);
index 18829cf..68bb838 100644 (file)
@@ -38,7 +38,7 @@ static int fb_notifier_callback(struct notifier_block *self,
        mutex_lock(&bd->ops_lock);
        if (bd->ops)
                if (!bd->ops->check_fb ||
-                   bd->ops->check_fb(evdata->info)) {
+                   bd->ops->check_fb(bd, evdata->info)) {
                        bd->props.fb_blank = *(int *)evdata->data;
                        if (bd->props.fb_blank == FB_BLANK_UNBLANK)
                                bd->props.state &= ~BL_CORE_FBBLANK;
@@ -269,7 +269,8 @@ EXPORT_SYMBOL(backlight_force_update);
  * ERR_PTR() or a pointer to the newly allocated device.
  */
 struct backlight_device *backlight_device_register(const char *name,
-               struct device *parent, void *devdata, const struct backlight_ops *ops)
+       struct device *parent, void *devdata, const struct backlight_ops *ops,
+       const struct backlight_properties *props)
 {
        struct backlight_device *new_bd;
        int rc;
@@ -289,6 +290,11 @@ struct backlight_device *backlight_device_register(const char *name,
        dev_set_name(&new_bd->dev, name);
        dev_set_drvdata(&new_bd->dev, devdata);
 
+       /* Set default properties */
+       if (props)
+               memcpy(&new_bd->props, props,
+                      sizeof(struct backlight_properties));
+
        rc = device_register(&new_bd->dev);
        if (rc) {
                kfree(new_bd);
index b4bcf80..73bdd84 100644 (file)
@@ -533,6 +533,7 @@ err_free_backlight_on:
 
 static int __devinit corgi_lcd_probe(struct spi_device *spi)
 {
+       struct backlight_properties props;
        struct corgi_lcd_platform_data *pdata = spi->dev.platform_data;
        struct corgi_lcd *lcd;
        int ret = 0;
@@ -559,13 +560,14 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi)
        lcd->power = FB_BLANK_POWERDOWN;
        lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
 
-       lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev,
-                                       lcd, &corgi_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = pdata->max_intensity;
+       lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd,
+                                               &corgi_bl_ops, &props);
        if (IS_ERR(lcd->bl_dev)) {
                ret = PTR_ERR(lcd->bl_dev);
                goto err_unregister_lcd;
        }
-       lcd->bl_dev->props.max_brightness = pdata->max_intensity;
        lcd->bl_dev->props.brightness = pdata->default_intensity;
        lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
 
index da86db4..1cce603 100644 (file)
@@ -170,6 +170,7 @@ static struct lcd_ops cr_lcd_ops = {
 
 static int cr_backlight_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct backlight_device *bdp;
        struct lcd_device *ldp;
        struct cr_panel *crp;
@@ -190,8 +191,9 @@ static int cr_backlight_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       bdp = backlight_device_register("cr-backlight",
-                                       &pdev->dev, NULL, &cr_backlight_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL,
+                                       &cr_backlight_ops, &props);
        if (IS_ERR(bdp)) {
                pci_dev_put(lpc_dev);
                return PTR_ERR(bdp);
@@ -220,9 +222,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        crp->cr_lcd_device = ldp;
        crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
        crp->cr_backlight_device->props.brightness = 0;
-       crp->cr_backlight_device->props.max_brightness = 0;
        cr_backlight_set_intensity(crp->cr_backlight_device);
-
        cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
 
        platform_set_drvdata(pdev, crp);
index 74cdc64..686e4a7 100644 (file)
@@ -105,6 +105,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
        struct da9034_backlight_pdata *pdata = pdev->dev.platform_data;
        struct da903x_backlight_data *data;
        struct backlight_device *bl;
+       struct backlight_properties props;
        int max_brightness;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -134,15 +135,15 @@ static int da903x_backlight_probe(struct platform_device *pdev)
                da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
                                DA9034_WLED_ISET(pdata->output_current));
 
-       bl = backlight_device_register(pdev->name, data->da903x_dev,
-                       data, &da903x_backlight_ops);
+       props.max_brightness = max_brightness;
+       bl = backlight_device_register(pdev->name, data->da903x_dev, data,
+                                      &da903x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                kfree(data);
                return PTR_ERR(bl);
        }
 
-       bl->props.max_brightness = max_brightness;
        bl->props.brightness = max_brightness;
 
        platform_set_drvdata(pdev, bl);
index e6d348e..312ca61 100644 (file)
@@ -78,6 +78,7 @@ static const struct backlight_ops genericbl_ops = {
 
 static int genericbl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct generic_bl_info *machinfo = pdev->dev.platform_data;
        const char *name = "generic-bl";
        struct backlight_device *bd;
@@ -89,14 +90,15 @@ static int genericbl_probe(struct platform_device *pdev)
        if (machinfo->name)
                name = machinfo->name;
 
-       bd = backlight_device_register (name,
-               &pdev->dev, NULL, &genericbl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = machinfo->max_intensity;
+       bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops,
+                                      &props);
        if (IS_ERR (bd))
                return PTR_ERR (bd);
 
        platform_set_drvdata(pdev, bd);
 
-       bd->props.max_brightness = machinfo->max_intensity;
        bd->props.power = FB_BLANK_UNBLANK;
        bd->props.brightness = machinfo->default_intensity;
        backlight_update_status(bd);
index f7cc528..267d23f 100644 (file)
@@ -105,16 +105,18 @@ static const struct backlight_ops hp680bl_ops = {
 
 static int __devinit hp680bl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct backlight_device *bd;
 
-       bd = backlight_device_register ("hp680-bl", &pdev->dev, NULL,
-                   &hp680bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = HP680_MAX_INTENSITY;
+       bd = backlight_device_register("hp680-bl", &pdev->dev, NULL,
+                                      &hp680bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
 
        platform_set_drvdata(pdev, bd);
 
-       bd->props.max_brightness = HP680_MAX_INTENSITY;
        bd->props.brightness = HP680_DEFAULT_INTENSITY;
        hp680bl_send_intensity(bd);
 
index db9071f..2f177b3 100644 (file)
@@ -101,10 +101,14 @@ static const struct backlight_ops jornada_bl_ops = {
 
 static int jornada_bl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        int ret;
        struct backlight_device *bd;
 
-       bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = BL_MAX_BRIGHT;
+       bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
+                                      &jornada_bl_ops, &props);
 
        if (IS_ERR(bd)) {
                ret = PTR_ERR(bd);
@@ -117,7 +121,6 @@ static int jornada_bl_probe(struct platform_device *pdev)
        /* note. make sure max brightness is set otherwise
           you will get seemingly non-related errors when
           trying to change brightness */
-       bd->props.max_brightness = BL_MAX_BRIGHT;
        jornada_bl_update_status(bd);
 
        platform_set_drvdata(pdev, bd);
index 939e7b8..f439a86 100644 (file)
@@ -141,20 +141,24 @@ static const struct backlight_ops kb3886bl_ops = {
 
 static int kb3886bl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct kb3886bl_machinfo *machinfo = pdev->dev.platform_data;
 
        bl_machinfo = machinfo;
        if (!machinfo->limit_mask)
                machinfo->limit_mask = -1;
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = machinfo->max_intensity;
        kb3886_backlight_device = backlight_device_register("kb3886-bl",
-               &pdev->dev, NULL, &kb3886bl_ops);
+                                                           &pdev->dev, NULL,
+                                                           &kb3886bl_ops,
+                                                           &props);
        if (IS_ERR(kb3886_backlight_device))
                return PTR_ERR(kb3886_backlight_device);
 
        platform_set_drvdata(pdev, kb3886_backlight_device);
 
-       kb3886_backlight_device->props.max_brightness = machinfo->max_intensity;
        kb3886_backlight_device->props.power = FB_BLANK_UNBLANK;
        kb3886_backlight_device->props.brightness = machinfo->default_intensity;
        backlight_update_status(kb3886_backlight_device);
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
new file mode 100644 (file)
index 0000000..74abd69
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * l4f00242t03.c -- support for Epson L4F00242T03 LCD
+ *
+ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *     Inspired by Marek Vasut work in l4f00242t03.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/lcd.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/l4f00242t03.h>
+
+struct l4f00242t03_priv {
+       struct spi_device       *spi;
+       struct lcd_device       *ld;
+       int lcd_on:1;
+       struct regulator *io_reg;
+       struct regulator *core_reg;
+};
+
+
+static void l4f00242t03_reset(unsigned int gpio)
+{
+       pr_debug("l4f00242t03_reset.\n");
+       gpio_set_value(gpio, 1);
+       mdelay(100);
+       gpio_set_value(gpio, 0);
+       mdelay(10);     /* tRES >= 100us */
+       gpio_set_value(gpio, 1);
+       mdelay(20);
+}
+
+#define param(x) ((x) | 0x100)
+
+static void l4f00242t03_lcd_init(struct spi_device *spi)
+{
+       struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
+       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
+
+       dev_dbg(&spi->dev, "initializing LCD\n");
+
+       if (priv->io_reg) {
+               regulator_set_voltage(priv->io_reg, 1800000, 1800000);
+               regulator_enable(priv->io_reg);
+       }
+
+       if (priv->core_reg) {
+               regulator_set_voltage(priv->core_reg, 2800000, 2800000);
+               regulator_enable(priv->core_reg);
+       }
+
+       gpio_set_value(pdata->data_enable_gpio, 1);
+       msleep(60);
+       spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16));
+}
+
+static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
+{
+       struct l4f00242t03_priv *priv = lcd_get_data(ld);
+       struct spi_device *spi = priv->spi;
+
+       const u16 slpout = 0x11;
+       const u16 dison = 0x29;
+
+       const u16 slpin = 0x10;
+       const u16 disoff = 0x28;
+
+       if (power) {
+               if (priv->lcd_on)
+                       return 0;
+
+               dev_dbg(&spi->dev, "turning on LCD\n");
+
+               spi_write(spi, (const u8 *)&slpout, sizeof(u16));
+               msleep(60);
+               spi_write(spi, (const u8 *)&dison, sizeof(u16));
+
+               priv->lcd_on = 1;
+       } else {
+               if (!priv->lcd_on)
+                       return 0;
+
+               dev_dbg(&spi->dev, "turning off LCD\n");
+
+               spi_write(spi, (const u8 *)&disoff, sizeof(u16));
+               msleep(60);
+               spi_write(spi, (const u8 *)&slpin, sizeof(u16));
+
+               priv->lcd_on = 0;
+       }
+
+       return 0;
+}
+
+static struct lcd_ops l4f_ops = {
+       .set_power      = l4f00242t03_lcd_power_set,
+       .get_power      = NULL,
+};
+
+static int __devinit l4f00242t03_probe(struct spi_device *spi)
+{
+       struct l4f00242t03_priv *priv;
+       struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
+       int ret;
+
+       if (pdata == NULL) {
+               dev_err(&spi->dev, "Uninitialized platform data.\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct l4f00242t03_priv), GFP_KERNEL);
+
+       if (priv == NULL) {
+               dev_err(&spi->dev, "No memory for this device.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev_set_drvdata(&spi->dev, priv);
+       spi->bits_per_word = 9;
+       spi_setup(spi);
+
+       priv->spi = spi;
+
+       ret = gpio_request(pdata->reset_gpio, "lcd l4f00242t03 reset");
+       if (ret) {
+               dev_err(&spi->dev,
+                       "Unable to get the lcd l4f00242t03 reset gpio.\n");
+               return ret;
+       }
+
+       ret = gpio_direction_output(pdata->reset_gpio, 1);
+       if (ret)
+               goto err2;
+
+       ret = gpio_request(pdata->data_enable_gpio,
+                               "lcd l4f00242t03 data enable");
+       if (ret) {
+               dev_err(&spi->dev,
+                       "Unable to get the lcd l4f00242t03 data en gpio.\n");
+               return ret;
+       }
+
+       ret = gpio_direction_output(pdata->data_enable_gpio, 0);
+       if (ret)
+               goto err3;
+
+       if (pdata->io_supply) {
+               priv->io_reg = regulator_get(NULL, pdata->io_supply);
+
+               if (IS_ERR(priv->io_reg)) {
+                       pr_err("%s: Unable to get the IO regulator\n",
+                                                               __func__);
+                       goto err3;
+               }
+       }
+
+       if (pdata->core_supply) {
+               priv->core_reg = regulator_get(NULL, pdata->core_supply);
+
+               if (IS_ERR(priv->core_reg)) {
+                       pr_err("%s: Unable to get the core regulator\n",
+                                                               __func__);
+                       goto err4;
+               }
+       }
+
+       priv->ld = lcd_device_register("l4f00242t03",
+                                       &spi->dev, priv, &l4f_ops);
+       if (IS_ERR(priv->ld)) {
+               ret = PTR_ERR(priv->ld);
+               goto err5;
+       }
+
+       /* Init the LCD */
+       l4f00242t03_reset(pdata->reset_gpio);
+       l4f00242t03_lcd_init(spi);
+       l4f00242t03_lcd_power_set(priv->ld, 1);
+
+       dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
+
+       return 0;
+
+err5:
+       if (priv->core_reg)
+               regulator_put(priv->core_reg);
+err4:
+       if (priv->io_reg)
+               regulator_put(priv->io_reg);
+err3:
+       gpio_free(pdata->data_enable_gpio);
+err2:
+       gpio_free(pdata->reset_gpio);
+err:
+       kfree(priv);
+
+       return ret;
+}
+
+static int __devexit l4f00242t03_remove(struct spi_device *spi)
+{
+       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data;
+
+       l4f00242t03_lcd_power_set(priv->ld, 0);
+       lcd_device_unregister(priv->ld);
+
+       gpio_free(pdata->data_enable_gpio);
+       gpio_free(pdata->reset_gpio);
+
+       if (priv->io_reg)
+               regulator_put(priv->core_reg);
+       if (priv->core_reg)
+               regulator_put(priv->io_reg);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static struct spi_driver l4f00242t03_driver = {
+       .driver = {
+               .name   = "l4f00242t03",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = l4f00242t03_probe,
+       .remove         = __devexit_p(l4f00242t03_remove),
+};
+
+static __init int l4f00242t03_init(void)
+{
+       return spi_register_driver(&l4f00242t03_driver);
+}
+
+static __exit void l4f00242t03_exit(void)
+{
+       spi_unregister_driver(&l4f00242t03_driver);
+}
+
+module_init(l4f00242t03_init);
+module_exit(l4f00242t03_exit);
+
+MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
+MODULE_DESCRIPTION("EPSON L4F00242T03 LCD");
+MODULE_LICENSE("GPL v2");
index 00a9591..7571bc2 100644 (file)
@@ -167,6 +167,7 @@ static int locomolcd_resume(struct locomo_dev *dev)
 
 static int locomolcd_probe(struct locomo_dev *ldev)
 {
+       struct backlight_properties props;
        unsigned long flags;
 
        local_irq_save(flags);
@@ -182,13 +183,16 @@ static int locomolcd_probe(struct locomo_dev *ldev)
 
        local_irq_restore(flags);
 
-       locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, &locomobl_data);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 4;
+       locomolcd_bl_device = backlight_device_register("locomo-bl",
+                                                       &ldev->dev, NULL,
+                                                       &locomobl_data, &props);
 
        if (IS_ERR (locomolcd_bl_device))
                return PTR_ERR (locomolcd_bl_device);
 
        /* Set up frontlight so that screen is readable */
-       locomolcd_bl_device->props.max_brightness = 4,
        locomolcd_bl_device->props.brightness = 2;
        locomolcd_set_intensity(locomolcd_bl_device);
 
index c267069..c91adaf 100644 (file)
@@ -104,6 +104,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
        struct max8925_backlight_pdata *pdata = NULL;
        struct max8925_backlight_data *data;
        struct backlight_device *bl;
+       struct backlight_properties props;
        struct resource *res;
        char name[MAX8925_NAME_SIZE];
        unsigned char value;
@@ -133,14 +134,15 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
        data->chip = chip;
        data->current_brightness = 0;
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = MAX_BRIGHTNESS;
        bl = backlight_device_register(name, &pdev->dev, data,
-                                       &max8925_backlight_ops);
+                                       &max8925_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                kfree(data);
                return PTR_ERR(bl);
        }
-       bl->props.max_brightness = MAX_BRIGHTNESS;
        bl->props.brightness = MAX_BRIGHTNESS;
 
        platform_set_drvdata(pdev, bl);
index 2e78b07..1b5d3fe 100644 (file)
@@ -139,6 +139,51 @@ static int mbp_dmi_match(const struct dmi_system_id *id)
 static const struct dmi_system_id __initdata mbp_device_table[] = {
        {
                .callback       = mbp_dmi_match,
+               .ident          = "MacBook 1,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBook 2,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBook 3,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBook 4,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBook 4,2",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"),
+               },
+               .driver_data    = (void *)&intel_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
                .ident          = "MacBookPro 3,1",
                .matches        = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
@@ -250,6 +295,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
 
 static int __init mbp_init(void)
 {
+       struct backlight_properties props;
        if (!dmi_check_system(mbp_device_table))
                return -ENODEV;
 
@@ -257,14 +303,17 @@ static int __init mbp_init(void)
                                                "Macbook Pro backlight"))
                return -ENXIO;
 
-       mbp_backlight_device = backlight_device_register("mbp_backlight",
-                                       NULL, NULL, &driver_data->backlight_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 15;
+       mbp_backlight_device = backlight_device_register("mbp_backlight", NULL,
+                                                        NULL,
+                                                        &driver_data->backlight_ops,
+                                                        &props);
        if (IS_ERR(mbp_backlight_device)) {
                release_region(driver_data->iostart, driver_data->iolen);
                return PTR_ERR(mbp_backlight_device);
        }
 
-       mbp_backlight_device->props.max_brightness = 15;
        mbp_backlight_device->props.brightness =
                driver_data->backlight_ops.get_brightness(mbp_backlight_device);
        backlight_update_status(mbp_backlight_device);
index a3a7f89..333d28e 100644 (file)
@@ -132,6 +132,7 @@ static const struct backlight_ops omapbl_ops = {
 
 static int omapbl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct backlight_device *dev;
        struct omap_backlight *bl;
        struct omap_backlight_config *pdata = pdev->dev.platform_data;
@@ -143,7 +144,10 @@ static int omapbl_probe(struct platform_device *pdev)
        if (unlikely(!bl))
                return -ENOMEM;
 
-       dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = OMAPBL_MAX_INTENSITY;
+       dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
+                                       &props);
        if (IS_ERR(dev)) {
                kfree(bl);
                return PTR_ERR(dev);
@@ -160,7 +164,6 @@ static int omapbl_probe(struct platform_device *pdev)
        omap_cfg_reg(PWL);      /* Conflicts with UART3 */
 
        dev->props.fb_blank = FB_BLANK_UNBLANK;
-       dev->props.max_brightness = OMAPBL_MAX_INTENSITY;
        dev->props.brightness = pdata->default_intensity;
        omapbl_update_status(dev);
 
index 075786e..809278c 100644 (file)
@@ -61,8 +61,10 @@ static const struct backlight_ops progearbl_ops = {
 
 static int progearbl_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        u8 temp;
        struct backlight_device *progear_backlight_device;
+       int ret;
 
        pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
        if (!pmu_dev) {
@@ -73,28 +75,37 @@ static int progearbl_probe(struct platform_device *pdev)
        sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
        if (!sb_dev) {
                printk("ALI 1533 SB not found.\n");
-               pci_dev_put(pmu_dev);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put_pmu;
        }
 
        /*     Set SB_MPS1 to enable brightness control. */
        pci_read_config_byte(sb_dev, SB_MPS1, &temp);
        pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
 
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
        progear_backlight_device = backlight_device_register("progear-bl",
                                                             &pdev->dev, NULL,
-                                                            &progearbl_ops);
-       if (IS_ERR(progear_backlight_device))
-               return PTR_ERR(progear_backlight_device);
+                                                            &progearbl_ops,
+                                                            &props);
+       if (IS_ERR(progear_backlight_device)) {
+               ret = PTR_ERR(progear_backlight_device);
+               goto put_sb;
+       }
 
        platform_set_drvdata(pdev, progear_backlight_device);
 
        progear_backlight_device->props.power = FB_BLANK_UNBLANK;
        progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
-       progear_backlight_device->props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
        progearbl_set_intensity(progear_backlight_device);
 
        return 0;
+put_sb:
+       pci_dev_put(sb_dev);
+put_pmu:
+       pci_dev_put(pmu_dev);
+       return ret;
 }
 
 static int progearbl_remove(struct platform_device *pdev)
index 9d2ec2a..b89eebc 100644 (file)
@@ -65,6 +65,7 @@ static const struct backlight_ops pwm_backlight_ops = {
 
 static int pwm_backlight_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
        struct backlight_device *bl;
        struct pwm_bl_data *pb;
@@ -100,15 +101,16 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        } else
                dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
-       bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
-                       pb, &pwm_backlight_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = data->max_brightness;
+       bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
+                                      &pwm_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                ret = PTR_ERR(bl);
                goto err_bl;
        }
 
-       bl->props.max_brightness = data->max_brightness;
        bl->props.brightness = data->dft_brightness;
        backlight_update_status(bl);
 
index e14ce4d..f57bbf1 100644 (file)
@@ -80,6 +80,7 @@ static const struct backlight_ops bl_ops = {
 static int __devinit tosa_bl_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
+       struct backlight_properties props;
        struct tosa_bl_data *data = kzalloc(sizeof(struct tosa_bl_data), GFP_KERNEL);
        int ret = 0;
        if (!data)
@@ -99,15 +100,16 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
        i2c_set_clientdata(client, data);
        data->i2c = client;
 
-       data->bl = backlight_device_register("tosa-bl", &client->dev,
-                       data, &bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 512 - 1;
+       data->bl = backlight_device_register("tosa-bl", &client->dev, data,
+                                            &bl_ops, &props);
        if (IS_ERR(data->bl)) {
                ret = PTR_ERR(data->bl);
                goto err_reg;
        }
 
        data->bl->props.brightness = 69;
-       data->bl->props.max_brightness = 512 - 1;
        data->bl->props.power = FB_BLANK_UNBLANK;
 
        backlight_update_status(data->bl);
index e32add3..a431270 100644 (file)
@@ -125,6 +125,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
        struct wm831x_backlight_pdata *pdata;
        struct wm831x_backlight_data *data;
        struct backlight_device *bl;
+       struct backlight_properties props;
        int ret, i, max_isel, isink_reg, dcdc_cfg;
 
        /* We need platform data */
@@ -191,15 +192,15 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
        data->current_brightness = 0;
        data->isink_reg = isink_reg;
 
-       bl = backlight_device_register("wm831x", &pdev->dev,
-                       data, &wm831x_backlight_ops);
+       props.max_brightness = max_isel;
+       bl = backlight_device_register("wm831x", &pdev->dev, data,
+                                      &wm831x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                kfree(data);
                return PTR_ERR(bl);
        }
 
-       bl->props.max_brightness = max_isel;
        bl->props.brightness = max_isel;
 
        platform_set_drvdata(pdev, bl);
index 814312a..23b2a8c 100644 (file)
@@ -433,7 +433,7 @@ static int bl_get_brightness(struct backlight_device *bd)
        return 0;
 }
 
-static struct backlight_ops bfin_lq043fb_bl_ops = {
+static const struct backlight_ops bfin_lq043fb_bl_ops = {
        .get_brightness = bl_get_brightness,
 };
 
@@ -501,6 +501,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct bfin_bf54xfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -645,10 +646,16 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
                goto out8;
        }
 #ifndef NO_BL_SUPPORT
-       bl_dev =
-           backlight_device_register("bf54x-bl", NULL, NULL,
-                                     &bfin_lq043fb_bl_ops);
-       bl_dev->props.max_brightness = 255;
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 255;
+       bl_dev = backlight_device_register("bf54x-bl", NULL, NULL,
+                                          &bfin_lq043fb_bl_ops, &props);
+       if (IS_ERR(bl_dev)) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": unable to register backlight.\n");
+               ret = -EINVAL;
+               goto out9;
+       }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops);
        lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n");
@@ -656,6 +663,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 
        return 0;
 
+out9:
+       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index 5653d08..31a2dec 100644 (file)
@@ -352,7 +352,7 @@ static int bl_get_brightness(struct backlight_device *bd)
        return 0;
 }
 
-static struct backlight_ops bfin_lq043fb_bl_ops = {
+static const struct backlight_ops bfin_lq043fb_bl_ops = {
        .get_brightness = bl_get_brightness,
 };
 
@@ -419,6 +419,7 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 {
+       struct backlight_properties props;
        struct bfin_t350mcqbfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -540,10 +541,16 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
                goto out8;
        }
 #ifndef NO_BL_SUPPORT
-       bl_dev =
-           backlight_device_register("bf52x-bl", NULL, NULL,
-                                     &bfin_lq043fb_bl_ops);
-       bl_dev->props.max_brightness = 255;
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 255;
+       bl_dev = backlight_device_register("bf52x-bl", NULL, NULL,
+                                          &bfin_lq043fb_bl_ops, &props);
+       if (IS_ERR(bl_dev)) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": unable to register backlight.\n");
+               ret = -EINVAL;
+               goto out9;
+       }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops);
        lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n");
@@ -551,6 +558,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 
        return 0;
 
+out9:
+       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index 443e3c8..2fb552a 100644 (file)
@@ -94,6 +94,7 @@ static struct backlight_ops nvidia_bl_ops = {
 
 void nvidia_bl_init(struct nvidia_par *par)
 {
+       struct backlight_properties props;
        struct fb_info *info = pci_get_drvdata(par->pci_dev);
        struct backlight_device *bd;
        char name[12];
@@ -109,7 +110,10 @@ void nvidia_bl_init(struct nvidia_par *par)
 
        snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 
-       bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops,
+                                      &props);
        if (IS_ERR(bd)) {
                info->bl_dev = NULL;
                printk(KERN_WARNING "nvidia: Backlight registration failed\n");
@@ -121,7 +125,6 @@ void nvidia_bl_init(struct nvidia_par *par)
                0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
                0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
 
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd->props.brightness = bd->props.max_brightness;
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index fcd6a61..59769e8 100644 (file)
@@ -486,6 +486,7 @@ static struct attribute_group taal_attr_group = {
 
 static int taal_probe(struct omap_dss_device *dssdev)
 {
+       struct backlight_properties props;
        struct taal_data *td;
        struct backlight_device *bldev;
        int r;
@@ -520,11 +521,16 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        /* if no platform set_backlight() defined, presume DSI backlight
         * control */
+       memset(&props, 0, sizeof(struct backlight_properties));
        if (!dssdev->set_backlight)
                td->use_dsi_bl = true;
 
+       if (td->use_dsi_bl)
+               props.max_brightness = 255;
+       else
+               props.max_brightness = 127;
        bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
-                       &taal_bl_ops);
+                                         &taal_bl_ops, &props);
        if (IS_ERR(bldev)) {
                r = PTR_ERR(bldev);
                goto err2;
@@ -534,13 +540,10 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        bldev->props.fb_blank = FB_BLANK_UNBLANK;
        bldev->props.power = FB_BLANK_UNBLANK;
-       if (td->use_dsi_bl) {
-               bldev->props.max_brightness = 255;
+       if (td->use_dsi_bl)
                bldev->props.brightness = 255;
-       } else {
-               bldev->props.max_brightness = 127;
+       else
                bldev->props.brightness = 127;
-       }
 
        taal_bl_update_status(bldev);
 
index d94c57f..618f36b 100644 (file)
@@ -338,6 +338,7 @@ static struct backlight_ops riva_bl_ops = {
 
 static void riva_bl_init(struct riva_par *par)
 {
+       struct backlight_properties props;
        struct fb_info *info = pci_get_drvdata(par->pdev);
        struct backlight_device *bd;
        char name[12];
@@ -353,7 +354,10 @@ static void riva_bl_init(struct riva_par *par)
 
        snprintf(name, sizeof(name), "rivabl%d", info->node);
 
-       bd = backlight_device_register(name, info->dev, par, &riva_bl_ops);
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+       bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,
+                                      &props);
        if (IS_ERR(bd)) {
                info->bl_dev = NULL;
                printk(KERN_WARNING "riva: Backlight registration failed\n");
@@ -365,7 +369,6 @@ static void riva_bl_init(struct riva_par *par)
                MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
                FB_BACKLIGHT_MAX);
 
-       bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd->props.brightness = bd->props.max_brightness;
        bd->props.power = FB_BLANK_UNBLANK;
        backlight_update_status(bd);
index 7405f07..5f85b59 100644 (file)
@@ -235,6 +235,7 @@ config NFS_COMMON
 
 source "net/sunrpc/Kconfig"
 source "fs/smbfs/Kconfig"
+source "fs/ceph/Kconfig"
 source "fs/cifs/Kconfig"
 source "fs/ncpfs/Kconfig"
 source "fs/coda/Kconfig"
index c3633aa..97f340f 100644 (file)
@@ -125,3 +125,4 @@ obj-$(CONFIG_OCFS2_FS)              += ocfs2/
 obj-$(CONFIG_BTRFS_FS)         += btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
 obj-$(CONFIG_EXOFS_FS)          += exofs/
+obj-$(CONFIG_CEPH_FS)          += ceph/
index 3f1f50d..7a4dee1 100644 (file)
@@ -153,6 +153,11 @@ struct btrfs_inode {
        unsigned ordered_data_close:1;
        unsigned dummy_inode:1;
 
+       /*
+        * always compress this one file
+        */
+       unsigned force_compress:1;
+
        struct inode vfs_inode;
 };
 
index a11a320..28b92a7 100644 (file)
@@ -478,7 +478,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
                        goto next;
                }
 
-               page = alloc_page(mapping_gfp_mask(mapping) | GFP_NOFS);
+               page = alloc_page(mapping_gfp_mask(mapping) & ~__GFP_FS);
                if (!page)
                        break;
 
index 8b5cfdd..0af2e38 100644 (file)
@@ -373,11 +373,13 @@ struct btrfs_super_block {
  * ones specified below then we will fail to mount
  */
 #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF   (1ULL << 0)
+#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL  (2ULL << 0)
 
 #define BTRFS_FEATURE_COMPAT_SUPP              0ULL
 #define BTRFS_FEATURE_COMPAT_RO_SUPP           0ULL
 #define BTRFS_FEATURE_INCOMPAT_SUPP            \
-       BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF
+       (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
+        BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)
 
 /*
  * A leaf is full of items. offset and size tell us where to find
@@ -1182,7 +1184,6 @@ struct btrfs_root {
 #define BTRFS_INODE_NOATIME            (1 << 9)
 #define BTRFS_INODE_DIRSYNC            (1 << 10)
 
-
 /* some macros to generate set/get funcs for the struct fields.  This
  * assumes there is a lefoo_to_cpu for every type, so lets make a simple
  * one for u8:
@@ -1842,7 +1843,7 @@ BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
 BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,
                         compat_flags, 64);
 BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,
-                        compat_flags, 64);
+                        compat_ro_flags, 64);
 BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,
                         incompat_flags, 64);
 BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
@@ -2310,7 +2311,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               u32 min_type);
 
 int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
-int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
+int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
+                             struct extent_state **cached_state);
 int btrfs_writepages(struct address_space *mapping,
                     struct writeback_control *wbc);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
@@ -2335,7 +2337,7 @@ int btrfs_init_cachep(void);
 void btrfs_destroy_cachep(void);
 long btrfs_ioctl_trans_end(struct file *file);
 struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
-                        struct btrfs_root *root);
+                        struct btrfs_root *root, int *was_new);
 int btrfs_commit_write(struct file *file, struct page *page,
                       unsigned from, unsigned to);
 struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
@@ -2386,7 +2388,6 @@ void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
 ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 /* super.c */
-u64 btrfs_parse_size(char *str);
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
 
index 0427183..11d0ad3 100644 (file)
@@ -263,13 +263,15 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
 static int verify_parent_transid(struct extent_io_tree *io_tree,
                                 struct extent_buffer *eb, u64 parent_transid)
 {
+       struct extent_state *cached_state = NULL;
        int ret;
 
        if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
                return 0;
 
-       lock_extent(io_tree, eb->start, eb->start + eb->len - 1, GFP_NOFS);
-       if (extent_buffer_uptodate(io_tree, eb) &&
+       lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
+                        0, &cached_state, GFP_NOFS);
+       if (extent_buffer_uptodate(io_tree, eb, cached_state) &&
            btrfs_header_generation(eb) == parent_transid) {
                ret = 0;
                goto out;
@@ -282,10 +284,10 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                       (unsigned long long)btrfs_header_generation(eb));
        }
        ret = 1;
-       clear_extent_buffer_uptodate(io_tree, eb);
+       clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
 out:
-       unlock_extent(io_tree, eb->start, eb->start + eb->len - 1,
-                     GFP_NOFS);
+       unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
+                            &cached_state, GFP_NOFS);
        return ret;
 }
 
@@ -2497,7 +2499,8 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
        int ret;
        struct inode *btree_inode = buf->first_page->mapping->host;
 
-       ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf);
+       ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf,
+                                    NULL);
        if (!ret)
                return ret;
 
index ba5c3fd..951ef09 100644 (file)
@@ -95,7 +95,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
        btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
        key.offset = 0;
 
-       inode = btrfs_iget(sb, &key, root);
+       inode = btrfs_iget(sb, &key, root, NULL);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto fail;
@@ -223,7 +223,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
 
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root));
+       dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
        if (!IS_ERR(dentry))
                dentry->d_op = &btrfs_dentry_operations;
        return dentry;
index 559f724..1727b26 100644 (file)
@@ -6561,6 +6561,7 @@ static noinline int invalidate_extent_cache(struct btrfs_root *root,
        struct btrfs_key key;
        struct inode *inode = NULL;
        struct btrfs_file_extent_item *fi;
+       struct extent_state *cached_state = NULL;
        u64 num_bytes;
        u64 skip_objectid = 0;
        u32 nritems;
@@ -6589,12 +6590,14 @@ static noinline int invalidate_extent_cache(struct btrfs_root *root,
                }
                num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
 
-               lock_extent(&BTRFS_I(inode)->io_tree, key.offset,
-                           key.offset + num_bytes - 1, GFP_NOFS);
+               lock_extent_bits(&BTRFS_I(inode)->io_tree, key.offset,
+                                key.offset + num_bytes - 1, 0, &cached_state,
+                                GFP_NOFS);
                btrfs_drop_extent_cache(inode, key.offset,
                                        key.offset + num_bytes - 1, 1);
-               unlock_extent(&BTRFS_I(inode)->io_tree, key.offset,
-                             key.offset + num_bytes - 1, GFP_NOFS);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree, key.offset,
+                                    key.offset + num_bytes - 1, &cached_state,
+                                    GFP_NOFS);
                cond_resched();
        }
        iput(inode);
index 7073cbb..c99121a 100644 (file)
@@ -513,7 +513,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        u64 last_end;
        int err;
        int set = 0;
+       int clear = 0;
 
+       if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY))
+               clear = 1;
 again:
        if (!prealloc && (mask & __GFP_WAIT)) {
                prealloc = alloc_extent_state(mask);
@@ -524,14 +527,20 @@ again:
        spin_lock(&tree->lock);
        if (cached_state) {
                cached = *cached_state;
-               *cached_state = NULL;
-               cached_state = NULL;
+
+               if (clear) {
+                       *cached_state = NULL;
+                       cached_state = NULL;
+               }
+
                if (cached && cached->tree && cached->start == start) {
-                       atomic_dec(&cached->refs);
+                       if (clear)
+                               atomic_dec(&cached->refs);
                        state = cached;
                        goto hit_next;
                }
-               free_extent_state(cached);
+               if (clear)
+                       free_extent_state(cached);
        }
        /*
         * this search will find the extents that end after
@@ -946,11 +955,11 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 }
 
 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
-                    gfp_t mask)
+                       struct extent_state **cached_state, gfp_t mask)
 {
        return set_extent_bit(tree, start, end,
                              EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE,
-                             0, NULL, NULL, mask);
+                             0, NULL, cached_state, mask);
 }
 
 int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
@@ -984,10 +993,11 @@ int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
 }
 
 static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
-                                u64 end, gfp_t mask)
+                                u64 end, struct extent_state **cached_state,
+                                gfp_t mask)
 {
        return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
-                               NULL, mask);
+                               cached_state, mask);
 }
 
 int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
@@ -1171,7 +1181,8 @@ out:
  * 1 is returned if we find something, 0 if nothing was in the tree
  */
 static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
-                                       u64 *start, u64 *end, u64 max_bytes)
+                                       u64 *start, u64 *end, u64 max_bytes,
+                                       struct extent_state **cached_state)
 {
        struct rb_node *node;
        struct extent_state *state;
@@ -1203,8 +1214,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
                                *end = state->end;
                        goto out;
                }
-               if (!found)
+               if (!found) {
                        *start = state->start;
+                       *cached_state = state;
+                       atomic_inc(&state->refs);
+               }
                found++;
                *end = state->end;
                cur_start = state->end + 1;
@@ -1336,10 +1350,11 @@ again:
        delalloc_start = *start;
        delalloc_end = 0;
        found = find_delalloc_range(tree, &delalloc_start, &delalloc_end,
-                                   max_bytes);
+                                   max_bytes, &cached_state);
        if (!found || delalloc_end <= *start) {
                *start = delalloc_start;
                *end = delalloc_end;
+               free_extent_state(cached_state);
                return found;
        }
 
@@ -1722,7 +1737,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
                }
 
                if (!uptodate) {
-                       clear_extent_uptodate(tree, start, end, GFP_NOFS);
+                       clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
                        ClearPageUptodate(page);
                        SetPageError(page);
                }
@@ -1750,7 +1765,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
 static void end_bio_extent_readpage(struct bio *bio, int err)
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec = bio->bi_io_vec;
        struct extent_io_tree *tree;
        u64 start;
        u64 end;
@@ -1773,7 +1789,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                else
                        whole_page = 0;
 
-               if (--bvec >= bio->bi_io_vec)
+               if (++bvec <= bvec_end)
                        prefetchw(&bvec->bv_page->flags);
 
                if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
@@ -1818,7 +1834,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                        }
                        check_page_locked(tree, page);
                }
-       } while (bvec >= bio->bi_io_vec);
+       } while (bvec <= bvec_end);
 
        bio_put(bio);
 }
@@ -2704,6 +2720,7 @@ int extent_readpages(struct extent_io_tree *tree,
 int extent_invalidatepage(struct extent_io_tree *tree,
                          struct page *page, unsigned long offset)
 {
+       struct extent_state *cached_state = NULL;
        u64 start = ((u64)page->index << PAGE_CACHE_SHIFT);
        u64 end = start + PAGE_CACHE_SIZE - 1;
        size_t blocksize = page->mapping->host->i_sb->s_blocksize;
@@ -2712,12 +2729,12 @@ int extent_invalidatepage(struct extent_io_tree *tree,
        if (start > end)
                return 0;
 
-       lock_extent(tree, start, end, GFP_NOFS);
+       lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS);
        wait_on_page_writeback(page);
        clear_extent_bit(tree, start, end,
                         EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
                         EXTENT_DO_ACCOUNTING,
-                        1, 1, NULL, GFP_NOFS);
+                        1, 1, &cached_state, GFP_NOFS);
        return 0;
 }
 
@@ -2920,16 +2937,17 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
                get_extent_t *get_extent)
 {
        struct inode *inode = mapping->host;
+       struct extent_state *cached_state = NULL;
        u64 start = iblock << inode->i_blkbits;
        sector_t sector = 0;
        size_t blksize = (1 << inode->i_blkbits);
        struct extent_map *em;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
-                   GFP_NOFS);
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
+                        0, &cached_state, GFP_NOFS);
        em = get_extent(inode, NULL, 0, start, blksize, 0);
-       unlock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
-                     GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, start,
+                            start + blksize - 1, &cached_state, GFP_NOFS);
        if (!em || IS_ERR(em))
                return 0;
 
@@ -2951,6 +2969,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        u32 flags = 0;
        u64 disko = 0;
        struct extent_map *em = NULL;
+       struct extent_state *cached_state = NULL;
        int end = 0;
        u64 em_start = 0, em_len = 0;
        unsigned long emflags;
@@ -2959,8 +2978,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        if (len == 0)
                return -EINVAL;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
-               GFP_NOFS);
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
+                        &cached_state, GFP_NOFS);
        em = get_extent(inode, NULL, 0, off, max - off, 0);
        if (!em)
                goto out;
@@ -3023,8 +3042,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 out_free:
        free_extent_map(em);
 out:
-       unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
-                       GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len,
+                            &cached_state, GFP_NOFS);
        return ret;
 }
 
@@ -3264,7 +3283,8 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
 }
 
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-                               struct extent_buffer *eb)
+                               struct extent_buffer *eb,
+                               struct extent_state **cached_state)
 {
        unsigned long i;
        struct page *page;
@@ -3274,7 +3294,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
        clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 
        clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-                             GFP_NOFS);
+                             cached_state, GFP_NOFS);
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                if (page)
@@ -3334,7 +3354,8 @@ int extent_range_uptodate(struct extent_io_tree *tree,
 }
 
 int extent_buffer_uptodate(struct extent_io_tree *tree,
-                          struct extent_buffer *eb)
+                          struct extent_buffer *eb,
+                          struct extent_state *cached_state)
 {
        int ret = 0;
        unsigned long num_pages;
@@ -3346,7 +3367,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
                return 1;
 
        ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-                          EXTENT_UPTODATE, 1, NULL);
+                          EXTENT_UPTODATE, 1, cached_state);
        if (ret)
                return ret;
 
index 36de250..bbab481 100644 (file)
@@ -163,6 +163,8 @@ int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
 int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                     int bits, struct extent_state **cached, gfp_t mask);
 int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
+int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
+                        struct extent_state **cached, gfp_t mask);
 int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
                    gfp_t mask);
 int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
@@ -196,7 +198,7 @@ int clear_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
 int clear_extent_ordered_metadata(struct extent_io_tree *tree, u64 start,
                                  u64 end, gfp_t mask);
 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
-                    gfp_t mask);
+                       struct extent_state **cached_state, gfp_t mask);
 int set_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
                     gfp_t mask);
 int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
@@ -281,9 +283,11 @@ int test_extent_buffer_dirty(struct extent_io_tree *tree,
 int set_extent_buffer_uptodate(struct extent_io_tree *tree,
                               struct extent_buffer *eb);
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-                               struct extent_buffer *eb);
+                               struct extent_buffer *eb,
+                               struct extent_state **cached_state);
 int extent_buffer_uptodate(struct extent_io_tree *tree,
-                          struct extent_buffer *eb);
+                          struct extent_buffer *eb,
+                          struct extent_state *cached_state);
 int map_extent_buffer(struct extent_buffer *eb, unsigned long offset,
                      unsigned long min_len, char **token, char **map,
                      unsigned long *map_start,
index 6ed434a..ee3323c 100644 (file)
@@ -123,7 +123,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
                    root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
 
        end_of_last_block = start_pos + num_bytes - 1;
-       err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
+       err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
+                                       NULL);
        if (err)
                return err;
 
@@ -753,6 +754,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
                         loff_t pos, unsigned long first_index,
                         unsigned long last_index, size_t write_bytes)
 {
+       struct extent_state *cached_state = NULL;
        int i;
        unsigned long index = pos >> PAGE_CACHE_SHIFT;
        struct inode *inode = fdentry(file)->d_inode;
@@ -781,16 +783,18 @@ again:
        }
        if (start_pos < inode->i_size) {
                struct btrfs_ordered_extent *ordered;
-               lock_extent(&BTRFS_I(inode)->io_tree,
-                           start_pos, last_pos - 1, GFP_NOFS);
+               lock_extent_bits(&BTRFS_I(inode)->io_tree,
+                                start_pos, last_pos - 1, 0, &cached_state,
+                                GFP_NOFS);
                ordered = btrfs_lookup_first_ordered_extent(inode,
                                                            last_pos - 1);
                if (ordered &&
                    ordered->file_offset + ordered->len > start_pos &&
                    ordered->file_offset < last_pos) {
                        btrfs_put_ordered_extent(ordered);
-                       unlock_extent(&BTRFS_I(inode)->io_tree,
-                                     start_pos, last_pos - 1, GFP_NOFS);
+                       unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                                            start_pos, last_pos - 1,
+                                            &cached_state, GFP_NOFS);
                        for (i = 0; i < num_pages; i++) {
                                unlock_page(pages[i]);
                                page_cache_release(pages[i]);
@@ -802,12 +806,13 @@ again:
                if (ordered)
                        btrfs_put_ordered_extent(ordered);
 
-               clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos,
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos,
                                  last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
-                                 EXTENT_DO_ACCOUNTING,
+                                 EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
                                  GFP_NOFS);
-               unlock_extent(&BTRFS_I(inode)->io_tree,
-                             start_pos, last_pos - 1, GFP_NOFS);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                                    start_pos, last_pos - 1, &cached_state,
+                                    GFP_NOFS);
        }
        for (i = 0; i < num_pages; i++) {
                clear_page_dirty_for_io(pages[i]);
index c41db6d..02bb099 100644 (file)
@@ -379,7 +379,8 @@ again:
         * change at any time if we discover bad compression ratios.
         */
        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) &&
-           btrfs_test_opt(root, COMPRESS)) {
+           (btrfs_test_opt(root, COMPRESS) ||
+            (BTRFS_I(inode)->force_compress))) {
                WARN_ON(pages);
                pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
 
@@ -483,8 +484,10 @@ again:
                nr_pages_ret = 0;
 
                /* flag the file so we don't compress in the future */
-               if (!btrfs_test_opt(root, FORCE_COMPRESS))
+               if (!btrfs_test_opt(root, FORCE_COMPRESS) &&
+                   !(BTRFS_I(inode)->force_compress)) {
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
+               }
        }
        if (will_compress) {
                *num_added += 1;
@@ -570,8 +573,8 @@ retry:
                        unsigned long nr_written = 0;
 
                        lock_extent(io_tree, async_extent->start,
-                                   async_extent->start +
-                                   async_extent->ram_size - 1, GFP_NOFS);
+                                        async_extent->start +
+                                        async_extent->ram_size - 1, GFP_NOFS);
 
                        /* allocate blocks */
                        ret = cow_file_range(inode, async_cow->locked_page,
@@ -1211,7 +1214,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
        else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
-       else if (!btrfs_test_opt(root, COMPRESS))
+       else if (!btrfs_test_opt(root, COMPRESS) &&
+                !(BTRFS_I(inode)->force_compress))
                ret = cow_file_range(inode, locked_page, start, end,
                                      page_started, nr_written, 1);
        else
@@ -1508,12 +1512,13 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end)
+int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
+                             struct extent_state **cached_state)
 {
        if ((end & (PAGE_CACHE_SIZE - 1)) == 0)
                WARN_ON(1);
        return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
-                                  GFP_NOFS);
+                                  cached_state, GFP_NOFS);
 }
 
 /* see btrfs_writepage_start_hook for details on why this is required */
@@ -1526,6 +1531,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
 {
        struct btrfs_writepage_fixup *fixup;
        struct btrfs_ordered_extent *ordered;
+       struct extent_state *cached_state = NULL;
        struct page *page;
        struct inode *inode;
        u64 page_start;
@@ -1544,7 +1550,8 @@ again:
        page_start = page_offset(page);
        page_end = page_offset(page) + PAGE_CACHE_SIZE - 1;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end, GFP_NOFS);
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end, 0,
+                        &cached_state, GFP_NOFS);
 
        /* already ordered? We're done */
        if (PagePrivate2(page))
@@ -1552,17 +1559,18 @@ again:
 
        ordered = btrfs_lookup_ordered_extent(inode, page_start);
        if (ordered) {
-               unlock_extent(&BTRFS_I(inode)->io_tree, page_start,
-                             page_end, GFP_NOFS);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start,
+                                    page_end, &cached_state, GFP_NOFS);
                unlock_page(page);
                btrfs_start_ordered_extent(inode, ordered, 1);
                goto again;
        }
 
-       btrfs_set_extent_delalloc(inode, page_start, page_end);
+       btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
        ClearPageChecked(page);
 out:
-       unlock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end, GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
+                            &cached_state, GFP_NOFS);
 out_page:
        unlock_page(page);
        page_cache_release(page);
@@ -1691,14 +1699,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        struct btrfs_trans_handle *trans;
        struct btrfs_ordered_extent *ordered_extent = NULL;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct extent_state *cached_state = NULL;
        int compressed = 0;
        int ret;
 
-       ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1);
+       ret = btrfs_dec_test_ordered_pending(inode, &ordered_extent, start,
+                                            end - start + 1);
        if (!ret)
                return 0;
-
-       ordered_extent = btrfs_lookup_ordered_extent(inode, start);
        BUG_ON(!ordered_extent);
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
@@ -1713,9 +1721,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                goto out;
        }
 
-       lock_extent(io_tree, ordered_extent->file_offset,
-                   ordered_extent->file_offset + ordered_extent->len - 1,
-                   GFP_NOFS);
+       lock_extent_bits(io_tree, ordered_extent->file_offset,
+                        ordered_extent->file_offset + ordered_extent->len - 1,
+                        0, &cached_state, GFP_NOFS);
 
        trans = btrfs_join_transaction(root, 1);
 
@@ -1742,9 +1750,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                   ordered_extent->len);
                BUG_ON(ret);
        }
-       unlock_extent(io_tree, ordered_extent->file_offset,
-                   ordered_extent->file_offset + ordered_extent->len - 1,
-                   GFP_NOFS);
+       unlock_extent_cached(io_tree, ordered_extent->file_offset,
+                            ordered_extent->file_offset +
+                            ordered_extent->len - 1, &cached_state, GFP_NOFS);
+
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
 
@@ -2153,7 +2162,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                found_key.objectid = found_key.offset;
                found_key.type = BTRFS_INODE_ITEM_KEY;
                found_key.offset = 0;
-               inode = btrfs_iget(root->fs_info->sb, &found_key, root);
+               inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
                if (IS_ERR(inode))
                        break;
 
@@ -3081,6 +3090,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_ordered_extent *ordered;
+       struct extent_state *cached_state = NULL;
        char *kaddr;
        u32 blocksize = root->sectorsize;
        pgoff_t index = from >> PAGE_CACHE_SHIFT;
@@ -3127,12 +3137,14 @@ again:
        }
        wait_on_page_writeback(page);
 
-       lock_extent(io_tree, page_start, page_end, GFP_NOFS);
+       lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state,
+                        GFP_NOFS);
        set_page_extent_mapped(page);
 
        ordered = btrfs_lookup_ordered_extent(inode, page_start);
        if (ordered) {
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+               unlock_extent_cached(io_tree, page_start, page_end,
+                                    &cached_state, GFP_NOFS);
                unlock_page(page);
                page_cache_release(page);
                btrfs_start_ordered_extent(inode, ordered, 1);
@@ -3140,13 +3152,15 @@ again:
                goto again;
        }
 
-       clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
+       clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
                          EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
-                         GFP_NOFS);
+                         0, 0, &cached_state, GFP_NOFS);
 
-       ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
+       ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+                                       &cached_state);
        if (ret) {
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+               unlock_extent_cached(io_tree, page_start, page_end,
+                                    &cached_state, GFP_NOFS);
                goto out_unlock;
        }
 
@@ -3159,7 +3173,8 @@ again:
        }
        ClearPageChecked(page);
        set_page_dirty(page);
-       unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+       unlock_extent_cached(io_tree, page_start, page_end, &cached_state,
+                            GFP_NOFS);
 
 out_unlock:
        if (ret)
@@ -3177,6 +3192,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_map *em;
+       struct extent_state *cached_state = NULL;
        u64 mask = root->sectorsize - 1;
        u64 hole_start = (inode->i_size + mask) & ~mask;
        u64 block_end = (size + mask) & ~mask;
@@ -3192,11 +3208,13 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                struct btrfs_ordered_extent *ordered;
                btrfs_wait_ordered_range(inode, hole_start,
                                         block_end - hole_start);
-               lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
+               lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
+                                &cached_state, GFP_NOFS);
                ordered = btrfs_lookup_ordered_extent(inode, hole_start);
                if (!ordered)
                        break;
-               unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
+               unlock_extent_cached(io_tree, hole_start, block_end - 1,
+                                    &cached_state, GFP_NOFS);
                btrfs_put_ordered_extent(ordered);
        }
 
@@ -3241,7 +3259,8 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                        break;
        }
 
-       unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
+       unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state,
+                            GFP_NOFS);
        return err;
 }
 
@@ -3639,6 +3658,7 @@ static noinline void init_btrfs_i(struct inode *inode)
        bi->index_cnt = (u64)-1;
        bi->last_unlink_trans = 0;
        bi->ordered_data_close = 0;
+       bi->force_compress = 0;
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
@@ -3687,7 +3707,7 @@ static struct inode *btrfs_iget_locked(struct super_block *s,
  * Returns in *is_new if the inode was read from disk
  */
 struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
-                        struct btrfs_root *root)
+                        struct btrfs_root *root, int *new)
 {
        struct inode *inode;
 
@@ -3702,6 +3722,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
 
                inode_tree_add(inode);
                unlock_new_inode(inode);
+               if (new)
+                       *new = 1;
        }
 
        return inode;
@@ -3754,7 +3776,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
                return NULL;
 
        if (location.type == BTRFS_INODE_ITEM_KEY) {
-               inode = btrfs_iget(dir->i_sb, &location, root);
+               inode = btrfs_iget(dir->i_sb, &location, root, NULL);
                return inode;
        }
 
@@ -3769,7 +3791,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
                else
                        inode = new_simple_dir(dir->i_sb, &location, sub_root);
        } else {
-               inode = btrfs_iget(dir->i_sb, &location, sub_root);
+               inode = btrfs_iget(dir->i_sb, &location, sub_root, NULL);
        }
        srcu_read_unlock(&root->fs_info->subvol_srcu, index);
 
@@ -4501,7 +4523,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
        if (err) {
                err = -ENOSPC;
-               goto out_unlock;
+               goto out_fail;
        }
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
@@ -4979,6 +5001,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
 {
        struct extent_io_tree *tree;
        struct btrfs_ordered_extent *ordered;
+       struct extent_state *cached_state = NULL;
        u64 page_start = page_offset(page);
        u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
 
@@ -4997,7 +5020,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
                btrfs_releasepage(page, GFP_NOFS);
                return;
        }
-       lock_extent(tree, page_start, page_end, GFP_NOFS);
+       lock_extent_bits(tree, page_start, page_end, 0, &cached_state,
+                        GFP_NOFS);
        ordered = btrfs_lookup_ordered_extent(page->mapping->host,
                                           page_offset(page));
        if (ordered) {
@@ -5008,7 +5032,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
                clear_extent_bit(tree, page_start, page_end,
                                 EXTENT_DIRTY | EXTENT_DELALLOC |
                                 EXTENT_LOCKED | EXTENT_DO_ACCOUNTING, 1, 0,
-                                NULL, GFP_NOFS);
+                                &cached_state, GFP_NOFS);
                /*
                 * whoever cleared the private bit is responsible
                 * for the finish_ordered_io
@@ -5018,11 +5042,13 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
                                                page_start, page_end);
                }
                btrfs_put_ordered_extent(ordered);
-               lock_extent(tree, page_start, page_end, GFP_NOFS);
+               cached_state = NULL;
+               lock_extent_bits(tree, page_start, page_end, 0, &cached_state,
+                                GFP_NOFS);
        }
        clear_extent_bit(tree, page_start, page_end,
                 EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
-                EXTENT_DO_ACCOUNTING, 1, 1, NULL, GFP_NOFS);
+                EXTENT_DO_ACCOUNTING, 1, 1, &cached_state, GFP_NOFS);
        __btrfs_releasepage(page, GFP_NOFS);
 
        ClearPageChecked(page);
@@ -5055,6 +5081,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_ordered_extent *ordered;
+       struct extent_state *cached_state = NULL;
        char *kaddr;
        unsigned long zero_start;
        loff_t size;
@@ -5093,7 +5120,8 @@ again:
        }
        wait_on_page_writeback(page);
 
-       lock_extent(io_tree, page_start, page_end, GFP_NOFS);
+       lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state,
+                        GFP_NOFS);
        set_page_extent_mapped(page);
 
        /*
@@ -5102,7 +5130,8 @@ again:
         */
        ordered = btrfs_lookup_ordered_extent(inode, page_start);
        if (ordered) {
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+               unlock_extent_cached(io_tree, page_start, page_end,
+                                    &cached_state, GFP_NOFS);
                unlock_page(page);
                btrfs_start_ordered_extent(inode, ordered, 1);
                btrfs_put_ordered_extent(ordered);
@@ -5116,13 +5145,15 @@ again:
         * is probably a better way to do this, but for now keep consistent with
         * prepare_pages in the normal write path.
         */
-       clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
+       clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
                          EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
-                         GFP_NOFS);
+                         0, 0, &cached_state, GFP_NOFS);
 
-       ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
+       ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+                                       &cached_state);
        if (ret) {
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+               unlock_extent_cached(io_tree, page_start, page_end,
+                                    &cached_state, GFP_NOFS);
                ret = VM_FAULT_SIGBUS;
                btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
                goto out_unlock;
@@ -5148,7 +5179,7 @@ again:
        BTRFS_I(inode)->last_trans = root->fs_info->generation;
        BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
 
-       unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+       unlock_extent_cached(io_tree, page_start, page_end, &cached_state, GFP_NOFS);
 
 out_unlock:
        btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
@@ -5827,6 +5858,7 @@ stop_trans:
 static long btrfs_fallocate(struct inode *inode, int mode,
                            loff_t offset, loff_t len)
 {
+       struct extent_state *cached_state = NULL;
        u64 cur_offset;
        u64 last_byte;
        u64 alloc_start;
@@ -5865,16 +5897,17 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                /* the extent lock is ordered inside the running
                 * transaction
                 */
-               lock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
-                           GFP_NOFS);
+               lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
+                                locked_end, 0, &cached_state, GFP_NOFS);
                ordered = btrfs_lookup_first_ordered_extent(inode,
                                                            alloc_end - 1);
                if (ordered &&
                    ordered->file_offset + ordered->len > alloc_start &&
                    ordered->file_offset < alloc_end) {
                        btrfs_put_ordered_extent(ordered);
-                       unlock_extent(&BTRFS_I(inode)->io_tree,
-                                     alloc_start, locked_end, GFP_NOFS);
+                       unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                                            alloc_start, locked_end,
+                                            &cached_state, GFP_NOFS);
                        /*
                         * we can't wait on the range with the transaction
                         * running or with the extent lock held
@@ -5916,8 +5949,8 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        break;
                }
        }
-       unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
-                     GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
+                            &cached_state, GFP_NOFS);
 
        btrfs_free_reserved_data_space(BTRFS_I(inode)->root, inode,
                                       alloc_end - alloc_start);
index 645a179..2845c6c 100644 (file)
@@ -48,6 +48,7 @@
 #include "print-tree.h"
 #include "volumes.h"
 #include "locking.h"
+#include "ctree.h"
 
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -474,7 +475,79 @@ out_unlock:
        return error;
 }
 
-static int btrfs_defrag_file(struct file *file)
+static int should_defrag_range(struct inode *inode, u64 start, u64 len,
+                              int thresh, u64 *last_len, u64 *skip,
+                              u64 *defrag_end)
+{
+       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct extent_map *em = NULL;
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       int ret = 1;
+
+
+       if (thresh == 0)
+               thresh = 256 * 1024;
+
+       /*
+        * make sure that once we start defragging and extent, we keep on
+        * defragging it
+        */
+       if (start < *defrag_end)
+               return 1;
+
+       *skip = 0;
+
+       /*
+        * hopefully we have this extent in the tree already, try without
+        * the full extent lock
+        */
+       read_lock(&em_tree->lock);
+       em = lookup_extent_mapping(em_tree, start, len);
+       read_unlock(&em_tree->lock);
+
+       if (!em) {
+               /* get the big lock and read metadata off disk */
+               lock_extent(io_tree, start, start + len - 1, GFP_NOFS);
+               em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
+               unlock_extent(io_tree, start, start + len - 1, GFP_NOFS);
+
+               if (!em)
+                       return 0;
+       }
+
+       /* this will cover holes, and inline extents */
+       if (em->block_start >= EXTENT_MAP_LAST_BYTE)
+               ret = 0;
+
+       /*
+        * we hit a real extent, if it is big don't bother defragging it again
+        */
+       if ((*last_len == 0 || *last_len >= thresh) && em->len >= thresh)
+               ret = 0;
+
+       /*
+        * last_len ends up being a counter of how many bytes we've defragged.
+        * every time we choose not to defrag an extent, we reset *last_len
+        * so that the next tiny extent will force a defrag.
+        *
+        * The end result of this is that tiny extents before a single big
+        * extent will force at least part of that big extent to be defragged.
+        */
+       if (ret) {
+               *last_len += len;
+               *defrag_end = extent_map_end(em);
+       } else {
+               *last_len = 0;
+               *skip = extent_map_end(em);
+               *defrag_end = 0;
+       }
+
+       free_extent_map(em);
+       return ret;
+}
+
+static int btrfs_defrag_file(struct file *file,
+                            struct btrfs_ioctl_defrag_range_args *range)
 {
        struct inode *inode = fdentry(file)->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -486,37 +559,96 @@ static int btrfs_defrag_file(struct file *file)
        unsigned long total_read = 0;
        u64 page_start;
        u64 page_end;
+       u64 last_len = 0;
+       u64 skip = 0;
+       u64 defrag_end = 0;
        unsigned long i;
        int ret;
 
-       ret = btrfs_check_data_free_space(root, inode, inode->i_size);
-       if (ret)
-               return -ENOSPC;
+       if (inode->i_size == 0)
+               return 0;
+
+       if (range->start + range->len > range->start) {
+               last_index = min_t(u64, inode->i_size - 1,
+                        range->start + range->len - 1) >> PAGE_CACHE_SHIFT;
+       } else {
+               last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT;
+       }
+
+       i = range->start >> PAGE_CACHE_SHIFT;
+       while (i <= last_index) {
+               if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
+                                       PAGE_CACHE_SIZE,
+                                       range->extent_thresh,
+                                       &last_len, &skip,
+                                       &defrag_end)) {
+                       unsigned long next;
+                       /*
+                        * the should_defrag function tells us how much to skip
+                        * bump our counter by the suggested amount
+                        */
+                       next = (skip + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+                       i = max(i + 1, next);
+                       continue;
+               }
 
-       mutex_lock(&inode->i_mutex);
-       last_index = inode->i_size >> PAGE_CACHE_SHIFT;
-       for (i = 0; i <= last_index; i++) {
                if (total_read % ra_pages == 0) {
                        btrfs_force_ra(inode->i_mapping, &file->f_ra, file, i,
                                       min(last_index, i + ra_pages - 1));
                }
                total_read++;
+               mutex_lock(&inode->i_mutex);
+               if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
+                       BTRFS_I(inode)->force_compress = 1;
+
+               ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
+               if (ret) {
+                       ret = -ENOSPC;
+                       break;
+               }
+
+               ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
+               if (ret) {
+                       btrfs_free_reserved_data_space(root, inode,
+                                                      PAGE_CACHE_SIZE);
+                       ret = -ENOSPC;
+                       break;
+               }
 again:
+               if (inode->i_size == 0 ||
+                   i > ((inode->i_size - 1) >> PAGE_CACHE_SHIFT)) {
+                       ret = 0;
+                       goto err_reservations;
+               }
+
                page = grab_cache_page(inode->i_mapping, i);
                if (!page)
-                       goto out_unlock;
+                       goto err_reservations;
+
                if (!PageUptodate(page)) {
                        btrfs_readpage(NULL, page);
                        lock_page(page);
                        if (!PageUptodate(page)) {
                                unlock_page(page);
                                page_cache_release(page);
-                               goto out_unlock;
+                               goto err_reservations;
                        }
                }
 
+               if (page->mapping != inode->i_mapping) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       goto again;
+               }
+
                wait_on_page_writeback(page);
 
+               if (PageDirty(page)) {
+                       btrfs_free_reserved_data_space(root, inode,
+                                                      PAGE_CACHE_SIZE);
+                       goto loop_unlock;
+               }
+
                page_start = (u64)page->index << PAGE_CACHE_SHIFT;
                page_end = page_start + PAGE_CACHE_SIZE - 1;
                lock_extent(io_tree, page_start, page_end, GFP_NOFS);
@@ -537,18 +669,54 @@ again:
                 * page if it is dirtied again later
                 */
                clear_page_dirty_for_io(page);
+               clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start,
+                                 page_end, EXTENT_DIRTY | EXTENT_DELALLOC |
+                                 EXTENT_DO_ACCOUNTING, GFP_NOFS);
 
-               btrfs_set_extent_delalloc(inode, page_start, page_end);
+               btrfs_set_extent_delalloc(inode, page_start, page_end, NULL);
+               ClearPageChecked(page);
                set_page_dirty(page);
                unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
+
+loop_unlock:
                unlock_page(page);
                page_cache_release(page);
+               mutex_unlock(&inode->i_mutex);
+
+               btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
                balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
+               i++;
+       }
+
+       if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO))
+               filemap_flush(inode->i_mapping);
+
+       if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) {
+               /* the filemap_flush will queue IO into the worker threads, but
+                * we have to make sure the IO is actually started and that
+                * ordered extents get created before we return
+                */
+               atomic_inc(&root->fs_info->async_submit_draining);
+               while (atomic_read(&root->fs_info->nr_async_submits) ||
+                     atomic_read(&root->fs_info->async_delalloc_pages)) {
+                       wait_event(root->fs_info->async_submit_wait,
+                          (atomic_read(&root->fs_info->nr_async_submits) == 0 &&
+                           atomic_read(&root->fs_info->async_delalloc_pages) == 0));
+               }
+               atomic_dec(&root->fs_info->async_submit_draining);
+
+               mutex_lock(&inode->i_mutex);
+               BTRFS_I(inode)->force_compress = 0;
+               mutex_unlock(&inode->i_mutex);
        }
 
-out_unlock:
-       mutex_unlock(&inode->i_mutex);
        return 0;
+
+err_reservations:
+       mutex_unlock(&inode->i_mutex);
+       btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
+       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
+       return ret;
 }
 
 static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
@@ -608,7 +776,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                        mod = 1;
                        sizestr++;
                }
-               new_size = btrfs_parse_size(sizestr);
+               new_size = memparse(sizestr, NULL);
                if (new_size == 0) {
                        ret = -EINVAL;
                        goto out_unlock;
@@ -743,6 +911,327 @@ out:
        return ret;
 }
 
+static noinline int key_in_sk(struct btrfs_key *key,
+                             struct btrfs_ioctl_search_key *sk)
+{
+       struct btrfs_key test;
+       int ret;
+
+       test.objectid = sk->min_objectid;
+       test.type = sk->min_type;
+       test.offset = sk->min_offset;
+
+       ret = btrfs_comp_cpu_keys(key, &test);
+       if (ret < 0)
+               return 0;
+
+       test.objectid = sk->max_objectid;
+       test.type = sk->max_type;
+       test.offset = sk->max_offset;
+
+       ret = btrfs_comp_cpu_keys(key, &test);
+       if (ret > 0)
+               return 0;
+       return 1;
+}
+
+static noinline int copy_to_sk(struct btrfs_root *root,
+                              struct btrfs_path *path,
+                              struct btrfs_key *key,
+                              struct btrfs_ioctl_search_key *sk,
+                              char *buf,
+                              unsigned long *sk_offset,
+                              int *num_found)
+{
+       u64 found_transid;
+       struct extent_buffer *leaf;
+       struct btrfs_ioctl_search_header sh;
+       unsigned long item_off;
+       unsigned long item_len;
+       int nritems;
+       int i;
+       int slot;
+       int found = 0;
+       int ret = 0;
+
+       leaf = path->nodes[0];
+       slot = path->slots[0];
+       nritems = btrfs_header_nritems(leaf);
+
+       if (btrfs_header_generation(leaf) > sk->max_transid) {
+               i = nritems;
+               goto advance_key;
+       }
+       found_transid = btrfs_header_generation(leaf);
+
+       for (i = slot; i < nritems; i++) {
+               item_off = btrfs_item_ptr_offset(leaf, i);
+               item_len = btrfs_item_size_nr(leaf, i);
+
+               if (item_len > BTRFS_SEARCH_ARGS_BUFSIZE)
+                       item_len = 0;
+
+               if (sizeof(sh) + item_len + *sk_offset >
+                   BTRFS_SEARCH_ARGS_BUFSIZE) {
+                       ret = 1;
+                       goto overflow;
+               }
+
+               btrfs_item_key_to_cpu(leaf, key, i);
+               if (!key_in_sk(key, sk))
+                       continue;
+
+               sh.objectid = key->objectid;
+               sh.offset = key->offset;
+               sh.type = key->type;
+               sh.len = item_len;
+               sh.transid = found_transid;
+
+               /* copy search result header */
+               memcpy(buf + *sk_offset, &sh, sizeof(sh));
+               *sk_offset += sizeof(sh);
+
+               if (item_len) {
+                       char *p = buf + *sk_offset;
+                       /* copy the item */
+                       read_extent_buffer(leaf, p,
+                                          item_off, item_len);
+                       *sk_offset += item_len;
+               }
+               found++;
+
+               if (*num_found >= sk->nr_items)
+                       break;
+       }
+advance_key:
+       ret = 0;
+       if (key->offset < (u64)-1 && key->offset < sk->max_offset)
+               key->offset++;
+       else if (key->type < (u8)-1 && key->type < sk->max_type) {
+               key->offset = 0;
+               key->type++;
+       } else if (key->objectid < (u64)-1 && key->objectid < sk->max_objectid) {
+               key->offset = 0;
+               key->type = 0;
+               key->objectid++;
+       } else
+               ret = 1;
+overflow:
+       *num_found += found;
+       return ret;
+}
+
+static noinline int search_ioctl(struct inode *inode,
+                                struct btrfs_ioctl_search_args *args)
+{
+       struct btrfs_root *root;
+       struct btrfs_key key;
+       struct btrfs_key max_key;
+       struct btrfs_path *path;
+       struct btrfs_ioctl_search_key *sk = &args->key;
+       struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
+       int ret;
+       int num_found = 0;
+       unsigned long sk_offset = 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       if (sk->tree_id == 0) {
+               /* search the root of the inode that was passed */
+               root = BTRFS_I(inode)->root;
+       } else {
+               key.objectid = sk->tree_id;
+               key.type = BTRFS_ROOT_ITEM_KEY;
+               key.offset = (u64)-1;
+               root = btrfs_read_fs_root_no_name(info, &key);
+               if (IS_ERR(root)) {
+                       printk(KERN_ERR "could not find root %llu\n",
+                              sk->tree_id);
+                       btrfs_free_path(path);
+                       return -ENOENT;
+               }
+       }
+
+       key.objectid = sk->min_objectid;
+       key.type = sk->min_type;
+       key.offset = sk->min_offset;
+
+       max_key.objectid = sk->max_objectid;
+       max_key.type = sk->max_type;
+       max_key.offset = sk->max_offset;
+
+       path->keep_locks = 1;
+
+       while(1) {
+               ret = btrfs_search_forward(root, &key, &max_key, path, 0,
+                                          sk->min_transid);
+               if (ret != 0) {
+                       if (ret > 0)
+                               ret = 0;
+                       goto err;
+               }
+               ret = copy_to_sk(root, path, &key, sk, args->buf,
+                                &sk_offset, &num_found);
+               btrfs_release_path(root, path);
+               if (ret || num_found >= sk->nr_items)
+                       break;
+
+       }
+       ret = 0;
+err:
+       sk->nr_items = num_found;
+       btrfs_free_path(path);
+       return ret;
+}
+
+static noinline int btrfs_ioctl_tree_search(struct file *file,
+                                          void __user *argp)
+{
+        struct btrfs_ioctl_search_args *args;
+        struct inode *inode;
+        int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       args = kmalloc(sizeof(*args), GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+
+       if (copy_from_user(args, argp, sizeof(*args))) {
+               kfree(args);
+               return -EFAULT;
+       }
+       inode = fdentry(file)->d_inode;
+       ret = search_ioctl(inode, args);
+       if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
+               ret = -EFAULT;
+       kfree(args);
+       return ret;
+}
+
+/*
+ * Search INODE_REFs to identify path name of 'dirid' directory
+ * in a 'tree_id' tree. and sets path name to 'name'.
+ */
+static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
+                               u64 tree_id, u64 dirid, char *name)
+{
+       struct btrfs_root *root;
+       struct btrfs_key key;
+       char *ptr;
+       int ret = -1;
+       int slot;
+       int len;
+       int total_len = 0;
+       struct btrfs_inode_ref *iref;
+       struct extent_buffer *l;
+       struct btrfs_path *path;
+
+       if (dirid == BTRFS_FIRST_FREE_OBJECTID) {
+               name[0]='\0';
+               return 0;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
+
+       key.objectid = tree_id;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       key.offset = (u64)-1;
+       root = btrfs_read_fs_root_no_name(info, &key);
+       if (IS_ERR(root)) {
+               printk(KERN_ERR "could not find root %llu\n", tree_id);
+               ret = -ENOENT;
+               goto out;
+       }
+
+       key.objectid = dirid;
+       key.type = BTRFS_INODE_REF_KEY;
+       key.offset = (u64)-1;
+
+       while(1) {
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out;
+
+               l = path->nodes[0];
+               slot = path->slots[0];
+               if (ret > 0 && slot > 0)
+                       slot--;
+               btrfs_item_key_to_cpu(l, &key, slot);
+
+               if (ret > 0 && (key.objectid != dirid ||
+                               key.type != BTRFS_INODE_REF_KEY)) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+
+               iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref);
+               len = btrfs_inode_ref_name_len(l, iref);
+               ptr -= len + 1;
+               total_len += len + 1;
+               if (ptr < name)
+                       goto out;
+
+               *(ptr + len) = '/';
+               read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len);
+
+               if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
+                       break;
+
+               btrfs_release_path(root, path);
+               key.objectid = key.offset;
+               key.offset = (u64)-1;
+               dirid = key.objectid;
+
+       }
+       if (ptr < name)
+               goto out;
+       memcpy(name, ptr, total_len);
+       name[total_len]='\0';
+       ret = 0;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+static noinline int btrfs_ioctl_ino_lookup(struct file *file,
+                                          void __user *argp)
+{
+        struct btrfs_ioctl_ino_lookup_args *args;
+        struct inode *inode;
+        int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       args = kmalloc(sizeof(*args), GFP_KERNEL);
+       if (copy_from_user(args, argp, sizeof(*args))) {
+               kfree(args);
+               return -EFAULT;
+       }
+       inode = fdentry(file)->d_inode;
+
+       if (args->treeid == 0)
+               args->treeid = BTRFS_I(inode)->root->root_key.objectid;
+
+       ret = btrfs_search_path_in_tree(BTRFS_I(inode)->root->fs_info,
+                                       args->treeid, args->objectid,
+                                       args->name);
+
+       if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
+               ret = -EFAULT;
+
+       kfree(args);
+       return ret;
+}
+
 static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                             void __user *arg)
 {
@@ -849,10 +1338,11 @@ out:
        return err;
 }
 
-static int btrfs_ioctl_defrag(struct file *file)
+static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
 {
        struct inode *inode = fdentry(file)->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_ioctl_defrag_range_args *range;
        int ret;
 
        ret = mnt_want_write(file->f_path.mnt);
@@ -873,7 +1363,30 @@ static int btrfs_ioctl_defrag(struct file *file)
                        ret = -EINVAL;
                        goto out;
                }
-               btrfs_defrag_file(file);
+
+               range = kzalloc(sizeof(*range), GFP_KERNEL);
+               if (!range) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               if (argp) {
+                       if (copy_from_user(range, argp,
+                                          sizeof(*range))) {
+                               ret = -EFAULT;
+                               kfree(range);
+                       }
+                       /* compression requires us to start the IO */
+                       if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) {
+                               range->flags |= BTRFS_DEFRAG_RANGE_START_IO;
+                               range->extent_thresh = (u32)-1;
+                       }
+               } else {
+                       /* the rest are all set to zero by kzalloc */
+                       range->len = (u64)-1;
+               }
+               btrfs_defrag_file(file, range);
+               kfree(range);
                break;
        }
 out:
@@ -1274,6 +1787,157 @@ out:
        return ret;
 }
 
+static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
+{
+       struct inode *inode = fdentry(file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_root *new_root;
+       struct btrfs_dir_item *di;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_path *path;
+       struct btrfs_key location;
+       struct btrfs_disk_key disk_key;
+       struct btrfs_super_block *disk_super;
+       u64 features;
+       u64 objectid = 0;
+       u64 dir_id;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (copy_from_user(&objectid, argp, sizeof(objectid)))
+               return -EFAULT;
+
+       if (!objectid)
+               objectid = root->root_key.objectid;
+
+       location.objectid = objectid;
+       location.type = BTRFS_ROOT_ITEM_KEY;
+       location.offset = (u64)-1;
+
+       new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
+       if (IS_ERR(new_root))
+               return PTR_ERR(new_root);
+
+       if (btrfs_root_refs(&new_root->root_item) == 0)
+               return -ENOENT;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->leave_spinning = 1;
+
+       trans = btrfs_start_transaction(root, 1);
+       if (!trans) {
+               btrfs_free_path(path);
+               return -ENOMEM;
+       }
+
+       dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
+       di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path,
+                                  dir_id, "default", 7, 1);
+       if (!di) {
+               btrfs_free_path(path);
+               btrfs_end_transaction(trans, root);
+               printk(KERN_ERR "Umm, you don't have the default dir item, "
+                      "this isn't going to work\n");
+               return -ENOENT;
+       }
+
+       btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key);
+       btrfs_set_dir_item_key(path->nodes[0], di, &disk_key);
+       btrfs_mark_buffer_dirty(path->nodes[0]);
+       btrfs_free_path(path);
+
+       disk_super = &root->fs_info->super_copy;
+       features = btrfs_super_incompat_flags(disk_super);
+       if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) {
+               features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL;
+               btrfs_set_super_incompat_flags(disk_super, features);
+       }
+       btrfs_end_transaction(trans, root);
+
+       return 0;
+}
+
+long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_ioctl_space_args space_args;
+       struct btrfs_ioctl_space_info space;
+       struct btrfs_ioctl_space_info *dest;
+       struct btrfs_ioctl_space_info *dest_orig;
+       struct btrfs_ioctl_space_info *user_dest;
+       struct btrfs_space_info *info;
+       int alloc_size;
+       int ret = 0;
+       int slot_count = 0;
+
+       if (copy_from_user(&space_args,
+                          (struct btrfs_ioctl_space_args __user *)arg,
+                          sizeof(space_args)))
+               return -EFAULT;
+
+       /* first we count slots */
+       rcu_read_lock();
+       list_for_each_entry_rcu(info, &root->fs_info->space_info, list)
+               slot_count++;
+       rcu_read_unlock();
+
+       /* space_slots == 0 means they are asking for a count */
+       if (space_args.space_slots == 0) {
+               space_args.total_spaces = slot_count;
+               goto out;
+       }
+       alloc_size = sizeof(*dest) * slot_count;
+       /* we generally have at most 6 or so space infos, one for each raid
+        * level.  So, a whole page should be more than enough for everyone
+        */
+       if (alloc_size > PAGE_CACHE_SIZE)
+               return -ENOMEM;
+
+       space_args.total_spaces = 0;
+       dest = kmalloc(alloc_size, GFP_NOFS);
+       if (!dest)
+               return -ENOMEM;
+       dest_orig = dest;
+
+       /* now we have a buffer to copy into */
+       rcu_read_lock();
+       list_for_each_entry_rcu(info, &root->fs_info->space_info, list) {
+               /* make sure we don't copy more than we allocated
+                * in our buffer
+                */
+               if (slot_count == 0)
+                       break;
+               slot_count--;
+
+               /* make sure userland has enough room in their buffer */
+               if (space_args.total_spaces >= space_args.space_slots)
+                       break;
+
+               space.flags = info->flags;
+               space.total_bytes = info->total_bytes;
+               space.used_bytes = info->bytes_used;
+               memcpy(dest, &space, sizeof(space));
+               dest++;
+               space_args.total_spaces++;
+       }
+       rcu_read_unlock();
+
+       user_dest = (struct btrfs_ioctl_space_info *)
+               (arg + sizeof(struct btrfs_ioctl_space_args));
+
+       if (copy_to_user(user_dest, dest_orig, alloc_size))
+               ret = -EFAULT;
+
+       kfree(dest_orig);
+out:
+       if (ret == 0 && copy_to_user(arg, &space_args, sizeof(space_args)))
+               ret = -EFAULT;
+
+       return ret;
+}
+
 /*
  * there are many ways the trans_start and trans_end ioctls can lead
  * to deadlocks.  They should only be used by applications that
@@ -1320,8 +1984,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_snap_create(file, argp, 1);
        case BTRFS_IOC_SNAP_DESTROY:
                return btrfs_ioctl_snap_destroy(file, argp);
+       case BTRFS_IOC_DEFAULT_SUBVOL:
+               return btrfs_ioctl_default_subvol(file, argp);
        case BTRFS_IOC_DEFRAG:
-               return btrfs_ioctl_defrag(file);
+               return btrfs_ioctl_defrag(file, NULL);
+       case BTRFS_IOC_DEFRAG_RANGE:
+               return btrfs_ioctl_defrag(file, argp);
        case BTRFS_IOC_RESIZE:
                return btrfs_ioctl_resize(root, argp);
        case BTRFS_IOC_ADD_DEV:
@@ -1338,6 +2006,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_trans_start(file);
        case BTRFS_IOC_TRANS_END:
                return btrfs_ioctl_trans_end(file);
+       case BTRFS_IOC_TREE_SEARCH:
+               return btrfs_ioctl_tree_search(file, argp);
+       case BTRFS_IOC_INO_LOOKUP:
+               return btrfs_ioctl_ino_lookup(file, argp);
+       case BTRFS_IOC_SPACE_INFO:
+               return btrfs_ioctl_space_info(root, argp);
        case BTRFS_IOC_SYNC:
                btrfs_sync_fs(file->f_dentry->d_sb, 1);
                return 0;
index bc49914..424694a 100644 (file)
@@ -30,12 +30,114 @@ struct btrfs_ioctl_vol_args {
        char name[BTRFS_PATH_NAME_MAX + 1];
 };
 
+#define BTRFS_INO_LOOKUP_PATH_MAX 4080
+struct btrfs_ioctl_ino_lookup_args {
+       __u64 treeid;
+       __u64 objectid;
+       char name[BTRFS_INO_LOOKUP_PATH_MAX];
+};
+
+struct btrfs_ioctl_search_key {
+       /* which root are we searching.  0 is the tree of tree roots */
+       __u64 tree_id;
+
+       /* keys returned will be >= min and <= max */
+       __u64 min_objectid;
+       __u64 max_objectid;
+
+       /* keys returned will be >= min and <= max */
+       __u64 min_offset;
+       __u64 max_offset;
+
+       /* max and min transids to search for */
+       __u64 min_transid;
+       __u64 max_transid;
+
+       /* keys returned will be >= min and <= max */
+       __u32 min_type;
+       __u32 max_type;
+
+       /*
+        * how many items did userland ask for, and how many are we
+        * returning
+        */
+       __u32 nr_items;
+
+       /* align to 64 bits */
+       __u32 unused;
+
+       /* some extra for later */
+       __u64 unused1;
+       __u64 unused2;
+       __u64 unused3;
+       __u64 unused4;
+};
+
+struct btrfs_ioctl_search_header {
+       __u64 transid;
+       __u64 objectid;
+       __u64 offset;
+       __u32 type;
+       __u32 len;
+};
+
+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
+/*
+ * the buf is an array of search headers where
+ * each header is followed by the actual item
+ * the type field is expanded to 32 bits for alignment
+ */
+struct btrfs_ioctl_search_args {
+       struct btrfs_ioctl_search_key key;
+       char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
+};
+
 struct btrfs_ioctl_clone_range_args {
   __s64 src_fd;
   __u64 src_offset, src_length;
   __u64 dest_offset;
 };
 
+/* flags for the defrag range ioctl */
+#define BTRFS_DEFRAG_RANGE_COMPRESS 1
+#define BTRFS_DEFRAG_RANGE_START_IO 2
+
+struct btrfs_ioctl_defrag_range_args {
+       /* start of the defrag operation */
+       __u64 start;
+
+       /* number of bytes to defrag, use (u64)-1 to say all */
+       __u64 len;
+
+       /*
+        * flags for the operation, which can include turning
+        * on compression for this one defrag
+        */
+       __u64 flags;
+
+       /*
+        * any extent bigger than this will be considered
+        * already defragged.  Use 0 to take the kernel default
+        * Use 1 to say every single extent must be rewritten
+        */
+       __u32 extent_thresh;
+
+       /* spare for later */
+       __u32 unused[5];
+};
+
+struct btrfs_ioctl_space_info {
+       __u64 flags;
+       __u64 total_bytes;
+       __u64 used_bytes;
+};
+
+struct btrfs_ioctl_space_args {
+       __u64 space_slots;
+       __u64 total_spaces;
+       struct btrfs_ioctl_space_info spaces[0];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
                                   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -67,4 +169,13 @@ struct btrfs_ioctl_clone_range_args {
                                   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
                                struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
+                               struct btrfs_ioctl_defrag_range_args)
+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+                                  struct btrfs_ioctl_search_args)
+#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
+                                  struct btrfs_ioctl_ino_lookup_args)
+#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
+#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
+                                   struct btrfs_ioctl_space_args)
 #endif
index 5c2a9e7..a8ffecd 100644 (file)
@@ -174,7 +174,6 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        if (!entry)
                return -ENOMEM;
 
-       mutex_lock(&tree->mutex);
        entry->file_offset = file_offset;
        entry->start = start;
        entry->len = len;
@@ -190,16 +189,17 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        INIT_LIST_HEAD(&entry->list);
        INIT_LIST_HEAD(&entry->root_extent_list);
 
+       spin_lock(&tree->lock);
        node = tree_insert(&tree->tree, file_offset,
                           &entry->rb_node);
        BUG_ON(node);
+       spin_unlock(&tree->lock);
 
        spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
        list_add_tail(&entry->root_extent_list,
                      &BTRFS_I(inode)->root->fs_info->ordered_extents);
        spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
 
-       mutex_unlock(&tree->mutex);
        BUG_ON(node);
        return 0;
 }
@@ -216,9 +216,9 @@ int btrfs_add_ordered_sum(struct inode *inode,
        struct btrfs_ordered_inode_tree *tree;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        list_add_tail(&sum->list, &entry->list);
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        return 0;
 }
 
@@ -232,15 +232,16 @@ int btrfs_add_ordered_sum(struct inode *inode,
  * to make sure this function only returns 1 once for a given ordered extent.
  */
 int btrfs_dec_test_ordered_pending(struct inode *inode,
+                                  struct btrfs_ordered_extent **cached,
                                   u64 file_offset, u64 io_size)
 {
        struct btrfs_ordered_inode_tree *tree;
        struct rb_node *node;
-       struct btrfs_ordered_extent *entry;
+       struct btrfs_ordered_extent *entry = NULL;
        int ret;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        node = tree_search(tree, file_offset);
        if (!node) {
                ret = 1;
@@ -264,7 +265,11 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
        else
                ret = 1;
 out:
-       mutex_unlock(&tree->mutex);
+       if (!ret && cached && entry) {
+               *cached = entry;
+               atomic_inc(&entry->refs);
+       }
+       spin_unlock(&tree->lock);
        return ret == 0;
 }
 
@@ -291,7 +296,7 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
 
 /*
  * remove an ordered extent from the tree.  No references are dropped
- * and you must wake_up entry->wait.  You must hold the tree mutex
+ * and you must wake_up entry->wait.  You must hold the tree lock
  * while you call this function.
  */
 static int __btrfs_remove_ordered_extent(struct inode *inode,
@@ -340,9 +345,9 @@ int btrfs_remove_ordered_extent(struct inode *inode,
        int ret;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        ret = __btrfs_remove_ordered_extent(inode, entry);
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        wake_up(&entry->wait);
 
        return ret;
@@ -567,7 +572,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
        struct btrfs_ordered_extent *entry = NULL;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        node = tree_search(tree, file_offset);
        if (!node)
                goto out;
@@ -578,7 +583,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
        if (entry)
                atomic_inc(&entry->refs);
 out:
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        return entry;
 }
 
@@ -594,7 +599,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset)
        struct btrfs_ordered_extent *entry = NULL;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        node = tree_search(tree, file_offset);
        if (!node)
                goto out;
@@ -602,7 +607,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset)
        entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
        atomic_inc(&entry->refs);
 out:
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        return entry;
 }
 
@@ -629,7 +634,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
        else
                offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize);
 
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        disk_i_size = BTRFS_I(inode)->disk_i_size;
 
        /* truncate file */
@@ -735,7 +740,7 @@ out:
         */
        if (ordered)
                __btrfs_remove_ordered_extent(inode, ordered);
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        if (ordered)
                wake_up(&ordered->wait);
        return ret;
@@ -762,7 +767,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
        if (!ordered)
                return 1;
 
-       mutex_lock(&tree->mutex);
+       spin_lock(&tree->lock);
        list_for_each_entry_reverse(ordered_sum, &ordered->list, list) {
                if (disk_bytenr >= ordered_sum->bytenr) {
                        num_sectors = ordered_sum->len / sectorsize;
@@ -777,7 +782,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
                }
        }
 out:
-       mutex_unlock(&tree->mutex);
+       spin_unlock(&tree->lock);
        btrfs_put_ordered_extent(ordered);
        return ret;
 }
index 9116c6d..c82f76a 100644 (file)
@@ -21,7 +21,7 @@
 
 /* one of these per inode */
 struct btrfs_ordered_inode_tree {
-       struct mutex mutex;
+       spinlock_t lock;
        struct rb_root tree;
        struct rb_node *last;
 };
@@ -128,7 +128,7 @@ static inline int btrfs_ordered_sum_size(struct btrfs_root *root,
 static inline void
 btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t)
 {
-       mutex_init(&t->mutex);
+       spin_lock_init(&t->lock);
        t->tree = RB_ROOT;
        t->last = NULL;
 }
@@ -137,7 +137,8 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry);
 int btrfs_remove_ordered_extent(struct inode *inode,
                                struct btrfs_ordered_extent *entry);
 int btrfs_dec_test_ordered_pending(struct inode *inode,
-                                      u64 file_offset, u64 io_size);
+                                  struct btrfs_ordered_extent **cached,
+                                  u64 file_offset, u64 io_size);
 int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
                             u64 start, u64 len, u64 disk_len, int tyep);
 int btrfs_add_ordered_sum(struct inode *inode,
index 0109e56..0b23942 100644 (file)
@@ -2659,7 +2659,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
                                        EXTENT_BOUNDARY, GFP_NOFS);
                        nr++;
                }
-               btrfs_set_extent_delalloc(inode, page_start, page_end);
+               btrfs_set_extent_delalloc(inode, page_start, page_end, NULL);
 
                set_page_dirty(page);
                dirty_page++;
@@ -3487,7 +3487,7 @@ static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
        key.objectid = objectid;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       inode = btrfs_iget(root->fs_info->sb, &key, root);
+       inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
        BUG_ON(IS_ERR(inode) || is_bad_inode(inode));
        BTRFS_I(inode)->index_cnt = group->key.objectid;
 
index f8b4521..9ac612e 100644 (file)
@@ -63,10 +63,10 @@ static void btrfs_put_super(struct super_block *sb)
 }
 
 enum {
-       Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
-       Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
-       Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl,
-       Opt_compress, Opt_compress_force, Opt_notreelog, Opt_ratio,
+       Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum,
+       Opt_nodatacow, Opt_max_extent, Opt_max_inline, Opt_alloc_start,
+       Opt_nobarrier, Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool,
+       Opt_noacl, Opt_compress, Opt_compress_force, Opt_notreelog, Opt_ratio,
        Opt_flushoncommit,
        Opt_discard, Opt_err,
 };
@@ -74,6 +74,7 @@ enum {
 static match_table_t tokens = {
        {Opt_degraded, "degraded"},
        {Opt_subvol, "subvol=%s"},
+       {Opt_subvolid, "subvolid=%d"},
        {Opt_device, "device=%s"},
        {Opt_nodatasum, "nodatasum"},
        {Opt_nodatacow, "nodatacow"},
@@ -95,31 +96,6 @@ static match_table_t tokens = {
        {Opt_err, NULL},
 };
 
-u64 btrfs_parse_size(char *str)
-{
-       u64 res;
-       int mult = 1;
-       char *end;
-       char last;
-
-       res = simple_strtoul(str, &end, 10);
-
-       last = end[0];
-       if (isalpha(last)) {
-               last = tolower(last);
-               switch (last) {
-               case 'g':
-                       mult *= 1024;
-               case 'm':
-                       mult *= 1024;
-               case 'k':
-                       mult *= 1024;
-               }
-               res = res * mult;
-       }
-       return res;
-}
-
 /*
  * Regular mount options parser.  Everything that is needed only when
  * reading in a new superblock is parsed here.
@@ -157,6 +133,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        btrfs_set_opt(info->mount_opt, DEGRADED);
                        break;
                case Opt_subvol:
+               case Opt_subvolid:
                case Opt_device:
                        /*
                         * These are parsed by btrfs_parse_early_options
@@ -214,7 +191,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_max_extent:
                        num = match_strdup(&args[0]);
                        if (num) {
-                               info->max_extent = btrfs_parse_size(num);
+                               info->max_extent = memparse(num, NULL);
                                kfree(num);
 
                                info->max_extent = max_t(u64,
@@ -226,7 +203,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_max_inline:
                        num = match_strdup(&args[0]);
                        if (num) {
-                               info->max_inline = btrfs_parse_size(num);
+                               info->max_inline = memparse(num, NULL);
                                kfree(num);
 
                                if (info->max_inline) {
@@ -241,7 +218,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_alloc_start:
                        num = match_strdup(&args[0]);
                        if (num) {
-                               info->alloc_start = btrfs_parse_size(num);
+                               info->alloc_start = memparse(num, NULL);
                                kfree(num);
                                printk(KERN_INFO
                                        "btrfs: allocations start at %llu\n",
@@ -292,12 +269,13 @@ out:
  * only when we need to allocate a new super block.
  */
 static int btrfs_parse_early_options(const char *options, fmode_t flags,
-               void *holder, char **subvol_name,
+               void *holder, char **subvol_name, u64 *subvol_objectid,
                struct btrfs_fs_devices **fs_devices)
 {
        substring_t args[MAX_OPT_ARGS];
        char *opts, *p;
        int error = 0;
+       int intarg;
 
        if (!options)
                goto out;
@@ -320,6 +298,18 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                case Opt_subvol:
                        *subvol_name = match_strdup(&args[0]);
                        break;
+               case Opt_subvolid:
+                       intarg = 0;
+                       error = match_int(&args[0], &intarg);
+                       if (!error) {
+                               /* we want the original fs_tree */
+                               if (!intarg)
+                                       *subvol_objectid =
+                                               BTRFS_FS_TREE_OBJECTID;
+                               else
+                                       *subvol_objectid = intarg;
+                       }
+                       break;
                case Opt_device:
                        error = btrfs_scan_one_device(match_strdup(&args[0]),
                                        flags, holder, fs_devices);
@@ -347,6 +337,110 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
        return error;
 }
 
+static struct dentry *get_default_root(struct super_block *sb,
+                                      u64 subvol_objectid)
+{
+       struct btrfs_root *root = sb->s_fs_info;
+       struct btrfs_root *new_root;
+       struct btrfs_dir_item *di;
+       struct btrfs_path *path;
+       struct btrfs_key location;
+       struct inode *inode;
+       struct dentry *dentry;
+       u64 dir_id;
+       int new = 0;
+
+       /*
+        * We have a specific subvol we want to mount, just setup location and
+        * go look up the root.
+        */
+       if (subvol_objectid) {
+               location.objectid = subvol_objectid;
+               location.type = BTRFS_ROOT_ITEM_KEY;
+               location.offset = (u64)-1;
+               goto find_root;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return ERR_PTR(-ENOMEM);
+       path->leave_spinning = 1;
+
+       /*
+        * Find the "default" dir item which points to the root item that we
+        * will mount by default if we haven't been given a specific subvolume
+        * to mount.
+        */
+       dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
+       di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
+       if (!di) {
+               /*
+                * Ok the default dir item isn't there.  This is weird since
+                * it's always been there, but don't freak out, just try and
+                * mount to root most subvolume.
+                */
+               btrfs_free_path(path);
+               dir_id = BTRFS_FIRST_FREE_OBJECTID;
+               new_root = root->fs_info->fs_root;
+               goto setup_root;
+       }
+
+       btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
+       btrfs_free_path(path);
+
+find_root:
+       new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
+       if (IS_ERR(new_root))
+               return ERR_PTR(PTR_ERR(new_root));
+
+       if (btrfs_root_refs(&new_root->root_item) == 0)
+               return ERR_PTR(-ENOENT);
+
+       dir_id = btrfs_root_dirid(&new_root->root_item);
+setup_root:
+       location.objectid = dir_id;
+       location.type = BTRFS_INODE_ITEM_KEY;
+       location.offset = 0;
+
+       inode = btrfs_iget(sb, &location, new_root, &new);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       /*
+        * If we're just mounting the root most subvol put the inode and return
+        * a reference to the dentry.  We will have already gotten a reference
+        * to the inode in btrfs_fill_super so we're good to go.
+        */
+       if (!new && sb->s_root->d_inode == inode) {
+               iput(inode);
+               return dget(sb->s_root);
+       }
+
+       if (new) {
+               const struct qstr name = { .name = "/", .len = 1 };
+
+               /*
+                * New inode, we need to make the dentry a sibling of s_root so
+                * everything gets cleaned up properly on unmount.
+                */
+               dentry = d_alloc(sb->s_root, &name);
+               if (!dentry) {
+                       iput(inode);
+                       return ERR_PTR(-ENOMEM);
+               }
+               d_splice_alias(inode, dentry);
+       } else {
+               /*
+                * We found the inode in cache, just find a dentry for it and
+                * put the reference to the inode we just got.
+                */
+               dentry = d_find_alias(inode);
+               iput(inode);
+       }
+
+       return dentry;
+}
+
 static int btrfs_fill_super(struct super_block *sb,
                            struct btrfs_fs_devices *fs_devices,
                            void *data, int silent)
@@ -380,7 +474,7 @@ static int btrfs_fill_super(struct super_block *sb,
        key.objectid = BTRFS_FIRST_FREE_OBJECTID;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root);
+       inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root, NULL);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto fail_close;
@@ -392,12 +486,6 @@ static int btrfs_fill_super(struct super_block *sb,
                err = -ENOMEM;
                goto fail_close;
        }
-#if 0
-       /* this does the super kobj at the same time */
-       err = btrfs_sysfs_add_super(tree_root->fs_info);
-       if (err)
-               goto fail_close;
-#endif
 
        sb->s_root = root_dentry;
 
@@ -489,19 +577,22 @@ static int btrfs_test_super(struct super_block *s, void *data)
 static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
                const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       char *subvol_name = NULL;
        struct block_device *bdev = NULL;
        struct super_block *s;
        struct dentry *root;
        struct btrfs_fs_devices *fs_devices = NULL;
        fmode_t mode = FMODE_READ;
+       char *subvol_name = NULL;
+       u64 subvol_objectid = 0;
        int error = 0;
+       int found = 0;
 
        if (!(flags & MS_RDONLY))
                mode |= FMODE_WRITE;
 
        error = btrfs_parse_early_options(data, mode, fs_type,
-                                         &subvol_name, &fs_devices);
+                                         &subvol_name, &subvol_objectid,
+                                         &fs_devices);
        if (error)
                return error;
 
@@ -530,6 +621,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
                        goto error_close_devices;
                }
 
+               found = 1;
                btrfs_close_devices(fs_devices);
        } else {
                char b[BDEVNAME_SIZE];
@@ -547,25 +639,35 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
                s->s_flags |= MS_ACTIVE;
        }
 
-       if (!strcmp(subvol_name, "."))
-               root = dget(s->s_root);
-       else {
-               mutex_lock(&s->s_root->d_inode->i_mutex);
-               root = lookup_one_len(subvol_name, s->s_root,
+       root = get_default_root(s, subvol_objectid);
+       if (IS_ERR(root)) {
+               error = PTR_ERR(root);
+               deactivate_locked_super(s);
+               goto error;
+       }
+       /* if they gave us a subvolume name bind mount into that */
+       if (strcmp(subvol_name, ".")) {
+               struct dentry *new_root;
+               mutex_lock(&root->d_inode->i_mutex);
+               new_root = lookup_one_len(subvol_name, root,
                                      strlen(subvol_name));
-               mutex_unlock(&s->s_root->d_inode->i_mutex);
+               mutex_unlock(&root->d_inode->i_mutex);
 
-               if (IS_ERR(root)) {
+               if (IS_ERR(new_root)) {
                        deactivate_locked_super(s);
-                       error = PTR_ERR(root);
-                       goto error_free_subvol_name;
+                       error = PTR_ERR(new_root);
+                       dput(root);
+                       goto error_close_devices;
                }
-               if (!root->d_inode) {
+               if (!new_root->d_inode) {
                        dput(root);
+                       dput(new_root);
                        deactivate_locked_super(s);
                        error = -ENXIO;
-                       goto error_free_subvol_name;
+                       goto error_close_devices;
                }
+               dput(root);
+               root = new_root;
        }
 
        mnt->mnt_sb = s;
@@ -580,6 +682,7 @@ error_close_devices:
        btrfs_close_devices(fs_devices);
 error_free_subvol_name:
        kfree(subvol_name);
+error:
        return error;
 }
 
@@ -624,14 +727,37 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct btrfs_root *root = btrfs_sb(dentry->d_sb);
        struct btrfs_super_block *disk_super = &root->fs_info->super_copy;
+       struct list_head *head = &root->fs_info->space_info;
+       struct btrfs_space_info *found;
+       u64 total_used = 0;
+       u64 data_used = 0;
        int bits = dentry->d_sb->s_blocksize_bits;
        __be32 *fsid = (__be32 *)root->fs_info->fsid;
 
+       rcu_read_lock();
+       list_for_each_entry_rcu(found, head, list) {
+               if (found->flags & (BTRFS_BLOCK_GROUP_DUP|
+                                   BTRFS_BLOCK_GROUP_RAID10|
+                                   BTRFS_BLOCK_GROUP_RAID1)) {
+                       total_used += found->bytes_used;
+                       if (found->flags & BTRFS_BLOCK_GROUP_DATA)
+                               data_used += found->bytes_used;
+                       else
+                               data_used += found->total_bytes;
+               }
+
+               total_used += found->bytes_used;
+               if (found->flags & BTRFS_BLOCK_GROUP_DATA)
+                       data_used += found->bytes_used;
+               else
+                       data_used += found->total_bytes;
+       }
+       rcu_read_unlock();
+
        buf->f_namelen = BTRFS_NAME_LEN;
        buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
-       buf->f_bfree = buf->f_blocks -
-               (btrfs_super_bytes_used(disk_super) >> bits);
-       buf->f_bavail = buf->f_bfree;
+       buf->f_bfree = buf->f_blocks - (total_used >> bits);
+       buf->f_bavail = buf->f_blocks - (data_used >> bits);
        buf->f_bsize = dentry->d_sb->s_blocksize;
        buf->f_type = BTRFS_SUPER_MAGIC;
 
index 2a36e23..2d654c1 100644 (file)
@@ -997,13 +997,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                mutex_unlock(&root->fs_info->trans_mutex);
 
-               if (flush_on_commit) {
+               if (flush_on_commit || snap_pending) {
                        btrfs_start_delalloc_inodes(root, 1);
                        ret = btrfs_wait_ordered_extents(root, 0, 1);
                        BUG_ON(ret);
-               } else if (snap_pending) {
-                       ret = btrfs_wait_ordered_extents(root, 0, 1);
-                       BUG_ON(ret);
                }
 
                /*
index 4a9434b..1255fcc 100644 (file)
@@ -445,7 +445,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
        key.objectid = objectid;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       inode = btrfs_iget(root->fs_info->sb, &key, root);
+       inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
        if (IS_ERR(inode)) {
                inode = NULL;
        } else if (is_bad_inode(inode)) {
index 41ecbb2..9df8e3f 100644 (file)
@@ -256,13 +256,13 @@ loop_lock:
                        wake_up(&fs_info->async_submit_wait);
 
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
-               submit_bio(cur->bi_rw, cur);
-               num_run++;
-               batch_run++;
 
                if (bio_rw_flagged(cur, BIO_RW_SYNCIO))
                        num_sync_run++;
 
+               submit_bio(cur->bi_rw, cur);
+               num_run++;
+               batch_run++;
                if (need_resched()) {
                        if (num_sync_run) {
                                blk_run_backing_dev(bdi, NULL);
@@ -325,16 +325,6 @@ loop_lock:
                num_sync_run = 0;
                blk_run_backing_dev(bdi, NULL);
        }
-
-       cond_resched();
-       if (again)
-               goto loop;
-
-       spin_lock(&device->io_lock);
-       if (device->pending_bios.head || device->pending_sync_bios.head)
-               goto loop_lock;
-       spin_unlock(&device->io_lock);
-
        /*
         * IO has already been through a long path to get here.  Checksumming,
         * async helper threads, perhaps compression.  We've done a pretty
@@ -346,6 +336,16 @@ loop_lock:
         * cared about found its way down here.
         */
        blk_run_backing_dev(bdi, NULL);
+
+       cond_resched();
+       if (again)
+               goto loop;
+
+       spin_lock(&device->io_lock);
+       if (device->pending_bios.head || device->pending_sync_bios.head)
+               goto loop_lock;
+       spin_unlock(&device->io_lock);
+
 done:
        return 0;
 }
@@ -365,6 +365,7 @@ static noinline int device_list_add(const char *path,
        struct btrfs_device *device;
        struct btrfs_fs_devices *fs_devices;
        u64 found_transid = btrfs_super_generation(disk_super);
+       char *name;
 
        fs_devices = find_fsid(disk_super->fsid);
        if (!fs_devices) {
@@ -411,6 +412,12 @@ static noinline int device_list_add(const char *path,
 
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
+       } else if (strcmp(device->name, path)) {
+               name = kstrdup(path, GFP_NOFS);
+               if (!name)
+                       return -ENOMEM;
+               kfree(device->name);
+               device->name = name;
        }
 
        if (found_transid > fs_devices->latest_trans) {
@@ -592,7 +599,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        goto error_close;
 
                disk_super = (struct btrfs_super_block *)bh->b_data;
-               devid = le64_to_cpu(disk_super->dev_item.devid);
+               devid = btrfs_stack_device_id(&disk_super->dev_item);
                if (devid != device->devid)
                        goto error_brelse;
 
@@ -694,7 +701,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
                goto error_close;
        }
        disk_super = (struct btrfs_super_block *)bh->b_data;
-       devid = le64_to_cpu(disk_super->dev_item.devid);
+       devid = btrfs_stack_device_id(&disk_super->dev_item);
        transid = btrfs_super_generation(disk_super);
        if (disk_super->label[0])
                printk(KERN_INFO "device label %s ", disk_super->label);
@@ -1187,7 +1194,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                        goto error_close;
                }
                disk_super = (struct btrfs_super_block *)bh->b_data;
-               devid = le64_to_cpu(disk_super->dev_item.devid);
+               devid = btrfs_stack_device_id(&disk_super->dev_item);
                dev_uuid = disk_super->dev_item.uuid;
                device = btrfs_find_device(root, devid, dev_uuid,
                                           disk_super->fsid);
diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig
new file mode 100644 (file)
index 0000000..04b8280
--- /dev/null
@@ -0,0 +1,27 @@
+config CEPH_FS
+        tristate "Ceph distributed file system (EXPERIMENTAL)"
+       depends on INET && EXPERIMENTAL
+       select LIBCRC32C
+       select CONFIG_CRYPTO_AES
+       help
+         Choose Y or M here to include support for mounting the
+         experimental Ceph distributed file system.  Ceph is an extremely
+         scalable file system designed to provide high performance,
+         reliable access to petabytes of storage.
+
+         More information at http://ceph.newdream.net/.
+
+         If unsure, say N.
+
+config CEPH_FS_PRETTYDEBUG
+       bool "Include file:line in ceph debug output"
+       depends on CEPH_FS
+       default n
+       help
+         If you say Y here, debug output will include a filename and
+         line to aid debugging.  This icnreases kernel size and slows
+         execution slightly when debug call sites are enabled (e.g.,
+         via CONFIG_DYNAMIC_DEBUG).
+
+         If unsure, say N.
+
diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile
new file mode 100644 (file)
index 0000000..6a660e6
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Makefile for CEPH filesystem.
+#
+
+ifneq ($(KERNELRELEASE),)
+
+obj-$(CONFIG_CEPH_FS) += ceph.o
+
+ceph-objs := super.o inode.o dir.o file.o addr.o ioctl.o \
+       export.o caps.o snap.o xattr.o \
+       messenger.o msgpool.o buffer.o pagelist.o \
+       mds_client.o mdsmap.o \
+       mon_client.o \
+       osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
+       debugfs.o \
+       auth.o auth_none.o \
+       crypto.o armor.o \
+       auth_x.o \
+       ceph_fs.o ceph_strings.o ceph_hash.o ceph_frag.o
+
+else
+#Otherwise we were called directly from the command
+# line; invoke the kernel build system.
+
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default: all
+
+all:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_FS=m modules
+
+modules_install:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_FS=m modules_install
+
+clean:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
+
+endif
diff --git a/fs/ceph/README b/fs/ceph/README
new file mode 100644 (file)
index 0000000..18352fa
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# The following files are shared by (and manually synchronized
+# between) the Ceph userland and kernel client.
+#
+# userland                  kernel
+src/include/ceph_fs.h      fs/ceph/ceph_fs.h
+src/include/ceph_fs.cc     fs/ceph/ceph_fs.c
+src/include/msgr.h         fs/ceph/msgr.h
+src/include/rados.h        fs/ceph/rados.h
+src/include/ceph_strings.cc fs/ceph/ceph_strings.c
+src/include/ceph_frag.h            fs/ceph/ceph_frag.h
+src/include/ceph_frag.cc    fs/ceph/ceph_frag.c
+src/include/ceph_hash.h            fs/ceph/ceph_hash.h
+src/include/ceph_hash.cc    fs/ceph/ceph_hash.c
+src/crush/crush.c          fs/ceph/crush/crush.c
+src/crush/crush.h          fs/ceph/crush/crush.h
+src/crush/mapper.c         fs/ceph/crush/mapper.c
+src/crush/mapper.h         fs/ceph/crush/mapper.h
+src/crush/hash.h           fs/ceph/crush/hash.h
+src/crush/hash.c           fs/ceph/crush/hash.c
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
new file mode 100644 (file)
index 0000000..23bb0ce
--- /dev/null
@@ -0,0 +1,1188 @@
+#include "ceph_debug.h"
+
+#include <linux/backing-dev.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>   /* generic_writepages */
+#include <linux/pagevec.h>
+#include <linux/task_io_accounting_ops.h>
+
+#include "super.h"
+#include "osd_client.h"
+
+/*
+ * Ceph address space ops.
+ *
+ * There are a few funny things going on here.
+ *
+ * The page->private field is used to reference a struct
+ * ceph_snap_context for _every_ dirty page.  This indicates which
+ * snapshot the page was logically dirtied in, and thus which snap
+ * context needs to be associated with the osd write during writeback.
+ *
+ * Similarly, struct ceph_inode_info maintains a set of counters to
+ * count dirty pages on the inode.  In the absense of snapshots,
+ * i_wrbuffer_ref == i_wrbuffer_ref_head == the dirty page count.
+ *
+ * When a snapshot is taken (that is, when the client receives
+ * notification that a snapshot was taken), each inode with caps and
+ * with dirty pages (dirty pages implies there is a cap) gets a new
+ * ceph_cap_snap in the i_cap_snaps list (which is sorted in ascending
+ * order, new snaps go to the tail).  The i_wrbuffer_ref_head count is
+ * moved to capsnap->dirty. (Unless a sync write is currently in
+ * progress.  In that case, the capsnap is said to be "pending", new
+ * writes cannot start, and the capsnap isn't "finalized" until the
+ * write completes (or fails) and a final size/mtime for the inode for
+ * that snap can be settled upon.)  i_wrbuffer_ref_head is reset to 0.
+ *
+ * On writeback, we must submit writes to the osd IN SNAP ORDER.  So,
+ * we look for the first capsnap in i_cap_snaps and write out pages in
+ * that snap context _only_.  Then we move on to the next capsnap,
+ * eventually reaching the "live" or "head" context (i.e., pages that
+ * are not yet snapped) and are writing the most recently dirtied
+ * pages.
+ *
+ * Invalidate and so forth must take care to ensure the dirty page
+ * accounting is preserved.
+ */
+
+#define CONGESTION_ON_THRESH(congestion_kb) (congestion_kb >> (PAGE_SHIFT-10))
+#define CONGESTION_OFF_THRESH(congestion_kb)                           \
+       (CONGESTION_ON_THRESH(congestion_kb) -                          \
+        (CONGESTION_ON_THRESH(congestion_kb) >> 2))
+
+
+
+/*
+ * Dirty a page.  Optimistically adjust accounting, on the assumption
+ * that we won't race with invalidate.  If we do, readjust.
+ */
+static int ceph_set_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode;
+       struct ceph_inode_info *ci;
+       int undo = 0;
+       struct ceph_snap_context *snapc;
+
+       if (unlikely(!mapping))
+               return !TestSetPageDirty(page);
+
+       if (TestSetPageDirty(page)) {
+               dout("%p set_page_dirty %p idx %lu -- already dirty\n",
+                    mapping->host, page, page->index);
+               return 0;
+       }
+
+       inode = mapping->host;
+       ci = ceph_inode(inode);
+
+       /*
+        * Note that we're grabbing a snapc ref here without holding
+        * any locks!
+        */
+       snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);
+
+       /* dirty the head */
+       spin_lock(&inode->i_lock);
+       if (ci->i_wrbuffer_ref_head == 0)
+               ci->i_head_snapc = ceph_get_snap_context(snapc);
+       ++ci->i_wrbuffer_ref_head;
+       if (ci->i_wrbuffer_ref == 0)
+               igrab(inode);
+       ++ci->i_wrbuffer_ref;
+       dout("%p set_page_dirty %p idx %lu head %d/%d -> %d/%d "
+            "snapc %p seq %lld (%d snaps)\n",
+            mapping->host, page, page->index,
+            ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref_head-1,
+            ci->i_wrbuffer_ref, ci->i_wrbuffer_ref_head,
+            snapc, snapc->seq, snapc->num_snaps);
+       spin_unlock(&inode->i_lock);
+
+       /* now adjust page */
+       spin_lock_irq(&mapping->tree_lock);
+       if (page->mapping) {    /* Race with truncate? */
+               WARN_ON_ONCE(!PageUptodate(page));
+
+               if (mapping_cap_account_dirty(mapping)) {
+                       __inc_zone_page_state(page, NR_FILE_DIRTY);
+                       __inc_bdi_stat(mapping->backing_dev_info,
+                                       BDI_RECLAIMABLE);
+                       task_io_account_write(PAGE_CACHE_SIZE);
+               }
+               radix_tree_tag_set(&mapping->page_tree,
+                               page_index(page), PAGECACHE_TAG_DIRTY);
+
+               /*
+                * Reference snap context in page->private.  Also set
+                * PagePrivate so that we get invalidatepage callback.
+                */
+               page->private = (unsigned long)snapc;
+               SetPagePrivate(page);
+       } else {
+               dout("ANON set_page_dirty %p (raced truncate?)\n", page);
+               undo = 1;
+       }
+
+       spin_unlock_irq(&mapping->tree_lock);
+
+       if (undo)
+               /* whoops, we failed to dirty the page */
+               ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+
+       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+       BUG_ON(!PageDirty(page));
+       return 1;
+}
+
+/*
+ * If we are truncating the full page (i.e. offset == 0), adjust the
+ * dirty page counters appropriately.  Only called if there is private
+ * data on the page.
+ */
+static void ceph_invalidatepage(struct page *page, unsigned long offset)
+{
+       struct inode *inode;
+       struct ceph_inode_info *ci;
+       struct ceph_snap_context *snapc = (void *)page->private;
+
+       BUG_ON(!PageLocked(page));
+       BUG_ON(!page->private);
+       BUG_ON(!PagePrivate(page));
+       BUG_ON(!page->mapping);
+
+       inode = page->mapping->host;
+
+       /*
+        * We can get non-dirty pages here due to races between
+        * set_page_dirty and truncate_complete_page; just spit out a
+        * warning, in case we end up with accounting problems later.
+        */
+       if (!PageDirty(page))
+               pr_err("%p invalidatepage %p page not dirty\n", inode, page);
+
+       if (offset == 0)
+               ClearPageChecked(page);
+
+       ci = ceph_inode(inode);
+       if (offset == 0) {
+               dout("%p invalidatepage %p idx %lu full dirty page %lu\n",
+                    inode, page, page->index, offset);
+               ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+               ceph_put_snap_context(snapc);
+               page->private = 0;
+               ClearPagePrivate(page);
+       } else {
+               dout("%p invalidatepage %p idx %lu partial dirty page\n",
+                    inode, page, page->index);
+       }
+}
+
+/* just a sanity check */
+static int ceph_releasepage(struct page *page, gfp_t g)
+{
+       struct inode *inode = page->mapping ? page->mapping->host : NULL;
+       dout("%p releasepage %p idx %lu\n", inode, page, page->index);
+       WARN_ON(PageDirty(page));
+       WARN_ON(page->private);
+       WARN_ON(PagePrivate(page));
+       return 0;
+}
+
+/*
+ * read a single page, without unlocking it.
+ */
+static int readpage_nounlock(struct file *filp, struct page *page)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+       int err = 0;
+       u64 len = PAGE_CACHE_SIZE;
+
+       dout("readpage inode %p file %p page %p index %lu\n",
+            inode, filp, page, page->index);
+       err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
+                                 page->index << PAGE_CACHE_SHIFT, &len,
+                                 ci->i_truncate_seq, ci->i_truncate_size,
+                                 &page, 1);
+       if (err == -ENOENT)
+               err = 0;
+       if (err < 0) {
+               SetPageError(page);
+               goto out;
+       } else if (err < PAGE_CACHE_SIZE) {
+               /* zero fill remainder of page */
+               zero_user_segment(page, err, PAGE_CACHE_SIZE);
+       }
+       SetPageUptodate(page);
+
+out:
+       return err < 0 ? err : 0;
+}
+
+static int ceph_readpage(struct file *filp, struct page *page)
+{
+       int r = readpage_nounlock(filp, page);
+       unlock_page(page);
+       return r;
+}
+
+/*
+ * Build a vector of contiguous pages from the provided page list.
+ */
+static struct page **page_vector_from_list(struct list_head *page_list,
+                                          unsigned *nr_pages)
+{
+       struct page **pages;
+       struct page *page;
+       int next_index, contig_pages = 0;
+
+       /* build page vector */
+       pages = kmalloc(sizeof(*pages) * *nr_pages, GFP_NOFS);
+       if (!pages)
+               return ERR_PTR(-ENOMEM);
+
+       BUG_ON(list_empty(page_list));
+       next_index = list_entry(page_list->prev, struct page, lru)->index;
+       list_for_each_entry_reverse(page, page_list, lru) {
+               if (page->index == next_index) {
+                       dout("readpages page %d %p\n", contig_pages, page);
+                       pages[contig_pages] = page;
+                       contig_pages++;
+                       next_index++;
+               } else {
+                       break;
+               }
+       }
+       *nr_pages = contig_pages;
+       return pages;
+}
+
+/*
+ * Read multiple pages.  Leave pages we don't read + unlock in page_list;
+ * the caller (VM) cleans them up.
+ */
+static int ceph_readpages(struct file *file, struct address_space *mapping,
+                         struct list_head *page_list, unsigned nr_pages)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+       int rc = 0;
+       struct page **pages;
+       struct pagevec pvec;
+       loff_t offset;
+       u64 len;
+
+       dout("readpages %p file %p nr_pages %d\n",
+            inode, file, nr_pages);
+
+       pages = page_vector_from_list(page_list, &nr_pages);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       /* guess read extent */
+       offset = pages[0]->index << PAGE_CACHE_SHIFT;
+       len = nr_pages << PAGE_CACHE_SHIFT;
+       rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
+                                offset, &len,
+                                ci->i_truncate_seq, ci->i_truncate_size,
+                                pages, nr_pages);
+       if (rc == -ENOENT)
+               rc = 0;
+       if (rc < 0)
+               goto out;
+
+       /* set uptodate and add to lru in pagevec-sized chunks */
+       pagevec_init(&pvec, 0);
+       for (; !list_empty(page_list) && len > 0;
+            rc -= PAGE_CACHE_SIZE, len -= PAGE_CACHE_SIZE) {
+               struct page *page =
+                       list_entry(page_list->prev, struct page, lru);
+
+               list_del(&page->lru);
+
+               if (rc < (int)PAGE_CACHE_SIZE) {
+                       /* zero (remainder of) page */
+                       int s = rc < 0 ? 0 : rc;
+                       zero_user_segment(page, s, PAGE_CACHE_SIZE);
+               }
+
+               if (add_to_page_cache(page, mapping, page->index, GFP_NOFS)) {
+                       page_cache_release(page);
+                       dout("readpages %p add_to_page_cache failed %p\n",
+                            inode, page);
+                       continue;
+               }
+               dout("readpages %p adding %p idx %lu\n", inode, page,
+                    page->index);
+               flush_dcache_page(page);
+               SetPageUptodate(page);
+               unlock_page(page);
+               if (pagevec_add(&pvec, page) == 0)
+                       pagevec_lru_add_file(&pvec);   /* add to lru */
+       }
+       pagevec_lru_add_file(&pvec);
+       rc = 0;
+
+out:
+       kfree(pages);
+       return rc;
+}
+
+/*
+ * Get ref for the oldest snapc for an inode with dirty data... that is, the
+ * only snap context we are allowed to write back.
+ *
+ * Caller holds i_lock.
+ */
+static struct ceph_snap_context *__get_oldest_context(struct inode *inode,
+                                                     u64 *snap_size)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_snap_context *snapc = NULL;
+       struct ceph_cap_snap *capsnap = NULL;
+
+       list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+               dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
+                    capsnap->context, capsnap->dirty_pages);
+               if (capsnap->dirty_pages) {
+                       snapc = ceph_get_snap_context(capsnap->context);
+                       if (snap_size)
+                               *snap_size = capsnap->size;
+                       break;
+               }
+       }
+       if (!snapc && ci->i_snap_realm) {
+               snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);
+               dout(" head snapc %p has %d dirty pages\n",
+                    snapc, ci->i_wrbuffer_ref_head);
+       }
+       return snapc;
+}
+
+static struct ceph_snap_context *get_oldest_context(struct inode *inode,
+                                                   u64 *snap_size)
+{
+       struct ceph_snap_context *snapc = NULL;
+
+       spin_lock(&inode->i_lock);
+       snapc = __get_oldest_context(inode, snap_size);
+       spin_unlock(&inode->i_lock);
+       return snapc;
+}
+
+/*
+ * Write a single page, but leave the page locked.
+ *
+ * If we get a write error, set the page error bit, but still adjust the
+ * dirty page accounting (i.e., page is no longer dirty).
+ */
+static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
+{
+       struct inode *inode;
+       struct ceph_inode_info *ci;
+       struct ceph_client *client;
+       struct ceph_osd_client *osdc;
+       loff_t page_off = page->index << PAGE_CACHE_SHIFT;
+       int len = PAGE_CACHE_SIZE;
+       loff_t i_size;
+       int err = 0;
+       struct ceph_snap_context *snapc;
+       u64 snap_size = 0;
+       long writeback_stat;
+
+       dout("writepage %p idx %lu\n", page, page->index);
+
+       if (!page->mapping || !page->mapping->host) {
+               dout("writepage %p - no mapping\n", page);
+               return -EFAULT;
+       }
+       inode = page->mapping->host;
+       ci = ceph_inode(inode);
+       client = ceph_inode_to_client(inode);
+       osdc = &client->osdc;
+
+       /* verify this is a writeable snap context */
+       snapc = (void *)page->private;
+       if (snapc == NULL) {
+               dout("writepage %p page %p not dirty?\n", inode, page);
+               goto out;
+       }
+       if (snapc != get_oldest_context(inode, &snap_size)) {
+               dout("writepage %p page %p snapc %p not writeable - noop\n",
+                    inode, page, (void *)page->private);
+               /* we should only noop if called by kswapd */
+               WARN_ON((current->flags & PF_MEMALLOC) == 0);
+               goto out;
+       }
+
+       /* is this a partial page at end of file? */
+       if (snap_size)
+               i_size = snap_size;
+       else
+               i_size = i_size_read(inode);
+       if (i_size < page_off + len)
+               len = i_size - page_off;
+
+       dout("writepage %p page %p index %lu on %llu~%u\n",
+            inode, page, page->index, page_off, len);
+
+       writeback_stat = atomic_long_inc_return(&client->writeback_count);
+       if (writeback_stat >
+           CONGESTION_ON_THRESH(client->mount_args->congestion_kb))
+               set_bdi_congested(&client->backing_dev_info, BLK_RW_ASYNC);
+
+       set_page_writeback(page);
+       err = ceph_osdc_writepages(osdc, ceph_vino(inode),
+                                  &ci->i_layout, snapc,
+                                  page_off, len,
+                                  ci->i_truncate_seq, ci->i_truncate_size,
+                                  &inode->i_mtime,
+                                  &page, 1, 0, 0, true);
+       if (err < 0) {
+               dout("writepage setting page/mapping error %d %p\n", err, page);
+               SetPageError(page);
+               mapping_set_error(&inode->i_data, err);
+               if (wbc)
+                       wbc->pages_skipped++;
+       } else {
+               dout("writepage cleaned page %p\n", page);
+               err = 0;  /* vfs expects us to return 0 */
+       }
+       page->private = 0;
+       ClearPagePrivate(page);
+       end_page_writeback(page);
+       ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+       ceph_put_snap_context(snapc);
+out:
+       return err;
+}
+
+static int ceph_writepage(struct page *page, struct writeback_control *wbc)
+{
+       int err;
+       struct inode *inode = page->mapping->host;
+       BUG_ON(!inode);
+       igrab(inode);
+       err = writepage_nounlock(page, wbc);
+       unlock_page(page);
+       iput(inode);
+       return err;
+}
+
+
+/*
+ * lame release_pages helper.  release_pages() isn't exported to
+ * modules.
+ */
+static void ceph_release_pages(struct page **pages, int num)
+{
+       struct pagevec pvec;
+       int i;
+
+       pagevec_init(&pvec, 0);
+       for (i = 0; i < num; i++) {
+               if (pagevec_add(&pvec, pages[i]) == 0)
+                       pagevec_release(&pvec);
+       }
+       pagevec_release(&pvec);
+}
+
+
+/*
+ * async writeback completion handler.
+ *
+ * If we get an error, set the mapping error bit, but not the individual
+ * page error bits.
+ */
+static void writepages_finish(struct ceph_osd_request *req,
+                             struct ceph_msg *msg)
+{
+       struct inode *inode = req->r_inode;
+       struct ceph_osd_reply_head *replyhead;
+       struct ceph_osd_op *op;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       unsigned wrote;
+       struct page *page;
+       int i;
+       struct ceph_snap_context *snapc = req->r_snapc;
+       struct address_space *mapping = inode->i_mapping;
+       struct writeback_control *wbc = req->r_wbc;
+       __s32 rc = -EIO;
+       u64 bytes = 0;
+       struct ceph_client *client = ceph_inode_to_client(inode);
+       long writeback_stat;
+       unsigned issued = __ceph_caps_issued(ci, NULL);
+
+       /* parse reply */
+       replyhead = msg->front.iov_base;
+       WARN_ON(le32_to_cpu(replyhead->num_ops) == 0);
+       op = (void *)(replyhead + 1);
+       rc = le32_to_cpu(replyhead->result);
+       bytes = le64_to_cpu(op->extent.length);
+
+       if (rc >= 0) {
+               /*
+                * Assume we wrote the pages we originally sent.  The
+                * osd might reply with fewer pages if our writeback
+                * raced with a truncation and was adjusted at the osd,
+                * so don't believe the reply.
+                */
+               wrote = req->r_num_pages;
+       } else {
+               wrote = 0;
+               mapping_set_error(mapping, rc);
+       }
+       dout("writepages_finish %p rc %d bytes %llu wrote %d (pages)\n",
+            inode, rc, bytes, wrote);
+
+       /* clean all pages */
+       for (i = 0; i < req->r_num_pages; i++) {
+               page = req->r_pages[i];
+               BUG_ON(!page);
+               WARN_ON(!PageUptodate(page));
+
+               writeback_stat =
+                       atomic_long_dec_return(&client->writeback_count);
+               if (writeback_stat <
+                   CONGESTION_OFF_THRESH(client->mount_args->congestion_kb))
+                       clear_bdi_congested(&client->backing_dev_info,
+                                           BLK_RW_ASYNC);
+
+               if (i >= wrote) {
+                       dout("inode %p skipping page %p\n", inode, page);
+                       wbc->pages_skipped++;
+               }
+               page->private = 0;
+               ClearPagePrivate(page);
+               ceph_put_snap_context(snapc);
+               dout("unlocking %d %p\n", i, page);
+               end_page_writeback(page);
+
+               /*
+                * We lost the cache cap, need to truncate the page before
+                * it is unlocked, otherwise we'd truncate it later in the
+                * page truncation thread, possibly losing some data that
+                * raced its way in
+                */
+               if ((issued & CEPH_CAP_FILE_CACHE) == 0)
+                       generic_error_remove_page(inode->i_mapping, page);
+
+               unlock_page(page);
+       }
+       dout("%p wrote+cleaned %d pages\n", inode, wrote);
+       ceph_put_wrbuffer_cap_refs(ci, req->r_num_pages, snapc);
+
+       ceph_release_pages(req->r_pages, req->r_num_pages);
+       if (req->r_pages_from_pool)
+               mempool_free(req->r_pages,
+                            ceph_client(inode->i_sb)->wb_pagevec_pool);
+       else
+               kfree(req->r_pages);
+       ceph_osdc_put_request(req);
+}
+
+/*
+ * allocate a page vec, either directly, or if necessary, via a the
+ * mempool.  we avoid the mempool if we can because req->r_num_pages
+ * may be less than the maximum write size.
+ */
+static void alloc_page_vec(struct ceph_client *client,
+                          struct ceph_osd_request *req)
+{
+       req->r_pages = kmalloc(sizeof(struct page *) * req->r_num_pages,
+                              GFP_NOFS);
+       if (!req->r_pages) {
+               req->r_pages = mempool_alloc(client->wb_pagevec_pool, GFP_NOFS);
+               req->r_pages_from_pool = 1;
+               WARN_ON(!req->r_pages);
+       }
+}
+
+/*
+ * initiate async writeback
+ */
+static int ceph_writepages_start(struct address_space *mapping,
+                                struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_client *client;
+       pgoff_t index, start, end;
+       int range_whole = 0;
+       int should_loop = 1;
+       pgoff_t max_pages = 0, max_pages_ever = 0;
+       struct ceph_snap_context *snapc = NULL, *last_snapc = NULL;
+       struct pagevec pvec;
+       int done = 0;
+       int rc = 0;
+       unsigned wsize = 1 << inode->i_blkbits;
+       struct ceph_osd_request *req = NULL;
+       int do_sync;
+       u64 snap_size = 0;
+
+       /*
+        * Include a 'sync' in the OSD request if this is a data
+        * integrity write (e.g., O_SYNC write or fsync()), or if our
+        * cap is being revoked.
+        */
+       do_sync = wbc->sync_mode == WB_SYNC_ALL;
+       if (ceph_caps_revoking(ci, CEPH_CAP_FILE_BUFFER))
+               do_sync = 1;
+       dout("writepages_start %p dosync=%d (mode=%s)\n",
+            inode, do_sync,
+            wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
+            (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD"));
+
+       client = ceph_inode_to_client(inode);
+       if (client->mount_state == CEPH_MOUNT_SHUTDOWN) {
+               pr_warning("writepage_start %p on forced umount\n", inode);
+               return -EIO; /* we're in a forced umount, don't write! */
+       }
+       if (client->mount_args->wsize && client->mount_args->wsize < wsize)
+               wsize = client->mount_args->wsize;
+       if (wsize < PAGE_CACHE_SIZE)
+               wsize = PAGE_CACHE_SIZE;
+       max_pages_ever = wsize >> PAGE_CACHE_SHIFT;
+
+       pagevec_init(&pvec, 0);
+
+       /* ?? */
+       if (wbc->nonblocking && bdi_write_congested(bdi)) {
+               dout(" writepages congested\n");
+               wbc->encountered_congestion = 1;
+               goto out_final;
+       }
+
+       /* where to start/end? */
+       if (wbc->range_cyclic) {
+               start = mapping->writeback_index; /* Start from prev offset */
+               end = -1;
+               dout(" cyclic, start at %lu\n", start);
+       } else {
+               start = wbc->range_start >> PAGE_CACHE_SHIFT;
+               end = wbc->range_end >> PAGE_CACHE_SHIFT;
+               if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+                       range_whole = 1;
+               should_loop = 0;
+               dout(" not cyclic, %lu to %lu\n", start, end);
+       }
+       index = start;
+
+retry:
+       /* find oldest snap context with dirty data */
+       ceph_put_snap_context(snapc);
+       snapc = get_oldest_context(inode, &snap_size);
+       if (!snapc) {
+               /* hmm, why does writepages get called when there
+                  is no dirty data? */
+               dout(" no snap context with dirty data?\n");
+               goto out;
+       }
+       dout(" oldest snapc is %p seq %lld (%d snaps)\n",
+            snapc, snapc->seq, snapc->num_snaps);
+       if (last_snapc && snapc != last_snapc) {
+               /* if we switched to a newer snapc, restart our scan at the
+                * start of the original file range. */
+               dout("  snapc differs from last pass, restarting at %lu\n",
+                    index);
+               index = start;
+       }
+       last_snapc = snapc;
+
+       while (!done && index <= end) {
+               unsigned i;
+               int first;
+               pgoff_t next;
+               int pvec_pages, locked_pages;
+               struct page *page;
+               int want;
+               u64 offset, len;
+               struct ceph_osd_request_head *reqhead;
+               struct ceph_osd_op *op;
+               long writeback_stat;
+
+               next = 0;
+               locked_pages = 0;
+               max_pages = max_pages_ever;
+
+get_more_pages:
+               first = -1;
+               want = min(end - index,
+                          min((pgoff_t)PAGEVEC_SIZE,
+                              max_pages - (pgoff_t)locked_pages) - 1)
+                       + 1;
+               pvec_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                                               PAGECACHE_TAG_DIRTY,
+                                               want);
+               dout("pagevec_lookup_tag got %d\n", pvec_pages);
+               if (!pvec_pages && !locked_pages)
+                       break;
+               for (i = 0; i < pvec_pages && locked_pages < max_pages; i++) {
+                       page = pvec.pages[i];
+                       dout("? %p idx %lu\n", page, page->index);
+                       if (locked_pages == 0)
+                               lock_page(page);  /* first page */
+                       else if (!trylock_page(page))
+                               break;
+
+                       /* only dirty pages, or our accounting breaks */
+                       if (unlikely(!PageDirty(page)) ||
+                           unlikely(page->mapping != mapping)) {
+                               dout("!dirty or !mapping %p\n", page);
+                               unlock_page(page);
+                               break;
+                       }
+                       if (!wbc->range_cyclic && page->index > end) {
+                               dout("end of range %p\n", page);
+                               done = 1;
+                               unlock_page(page);
+                               break;
+                       }
+                       if (next && (page->index != next)) {
+                               dout("not consecutive %p\n", page);
+                               unlock_page(page);
+                               break;
+                       }
+                       if (wbc->sync_mode != WB_SYNC_NONE) {
+                               dout("waiting on writeback %p\n", page);
+                               wait_on_page_writeback(page);
+                       }
+                       if ((snap_size && page_offset(page) > snap_size) ||
+                           (!snap_size &&
+                            page_offset(page) > i_size_read(inode))) {
+                               dout("%p page eof %llu\n", page, snap_size ?
+                                    snap_size : i_size_read(inode));
+                               done = 1;
+                               unlock_page(page);
+                               break;
+                       }
+                       if (PageWriteback(page)) {
+                               dout("%p under writeback\n", page);
+                               unlock_page(page);
+                               break;
+                       }
+
+                       /* only if matching snap context */
+                       if (snapc != (void *)page->private) {
+                               dout("page snapc %p != oldest %p\n",
+                                    (void *)page->private, snapc);
+                               unlock_page(page);
+                               if (!locked_pages)
+                                       continue; /* keep looking for snap */
+                               break;
+                       }
+
+                       if (!clear_page_dirty_for_io(page)) {
+                               dout("%p !clear_page_dirty_for_io\n", page);
+                               unlock_page(page);
+                               break;
+                       }
+
+                       /* ok */
+                       if (locked_pages == 0) {
+                               /* prepare async write request */
+                               offset = page->index << PAGE_CACHE_SHIFT;
+                               len = wsize;
+                               req = ceph_osdc_new_request(&client->osdc,
+                                           &ci->i_layout,
+                                           ceph_vino(inode),
+                                           offset, &len,
+                                           CEPH_OSD_OP_WRITE,
+                                           CEPH_OSD_FLAG_WRITE |
+                                                   CEPH_OSD_FLAG_ONDISK,
+                                           snapc, do_sync,
+                                           ci->i_truncate_seq,
+                                           ci->i_truncate_size,
+                                           &inode->i_mtime, true, 1);
+                               max_pages = req->r_num_pages;
+
+                               alloc_page_vec(client, req);
+                               req->r_callback = writepages_finish;
+                               req->r_inode = inode;
+                               req->r_wbc = wbc;
+                       }
+
+                       /* note position of first page in pvec */
+                       if (first < 0)
+                               first = i;
+                       dout("%p will write page %p idx %lu\n",
+                            inode, page, page->index);
+
+                       writeback_stat = atomic_long_inc_return(&client->writeback_count);
+                       if (writeback_stat > CONGESTION_ON_THRESH(client->mount_args->congestion_kb)) {
+                               set_bdi_congested(&client->backing_dev_info, BLK_RW_ASYNC);
+                       }
+
+                       set_page_writeback(page);
+                       req->r_pages[locked_pages] = page;
+                       locked_pages++;
+                       next = page->index + 1;
+               }
+
+               /* did we get anything? */
+               if (!locked_pages)
+                       goto release_pvec_pages;
+               if (i) {
+                       int j;
+                       BUG_ON(!locked_pages || first < 0);
+
+                       if (pvec_pages && i == pvec_pages &&
+                           locked_pages < max_pages) {
+                               dout("reached end pvec, trying for more\n");
+                               pagevec_reinit(&pvec);
+                               goto get_more_pages;
+                       }
+
+                       /* shift unused pages over in the pvec...  we
+                        * will need to release them below. */
+                       for (j = i; j < pvec_pages; j++) {
+                               dout(" pvec leftover page %p\n",
+                                    pvec.pages[j]);
+                               pvec.pages[j-i+first] = pvec.pages[j];
+                       }
+                       pvec.nr -= i-first;
+               }
+
+               /* submit the write */
+               offset = req->r_pages[0]->index << PAGE_CACHE_SHIFT;
+               len = min((snap_size ? snap_size : i_size_read(inode)) - offset,
+                         (u64)locked_pages << PAGE_CACHE_SHIFT);
+               dout("writepages got %d pages at %llu~%llu\n",
+                    locked_pages, offset, len);
+
+               /* revise final length, page count */
+               req->r_num_pages = locked_pages;
+               reqhead = req->r_request->front.iov_base;
+               op = (void *)(reqhead + 1);
+               op->extent.length = cpu_to_le64(len);
+               op->payload_len = cpu_to_le32(len);
+               req->r_request->hdr.data_len = cpu_to_le32(len);
+
+               ceph_osdc_start_request(&client->osdc, req, true);
+               req = NULL;
+
+               /* continue? */
+               index = next;
+               wbc->nr_to_write -= locked_pages;
+               if (wbc->nr_to_write <= 0)
+                       done = 1;
+
+release_pvec_pages:
+               dout("pagevec_release on %d pages (%p)\n", (int)pvec.nr,
+                    pvec.nr ? pvec.pages[0] : NULL);
+               pagevec_release(&pvec);
+
+               if (locked_pages && !done)
+                       goto retry;
+       }
+
+       if (should_loop && !done) {
+               /* more to do; loop back to beginning of file */
+               dout("writepages looping back to beginning of file\n");
+               should_loop = 0;
+               index = 0;
+               goto retry;
+       }
+
+       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+               mapping->writeback_index = index;
+
+out:
+       if (req)
+               ceph_osdc_put_request(req);
+       if (rc > 0)
+               rc = 0;  /* vfs expects us to return 0 */
+       ceph_put_snap_context(snapc);
+       dout("writepages done, rc = %d\n", rc);
+out_final:
+       return rc;
+}
+
+
+
+/*
+ * See if a given @snapc is either writeable, or already written.
+ */
+static int context_is_writeable_or_written(struct inode *inode,
+                                          struct ceph_snap_context *snapc)
+{
+       struct ceph_snap_context *oldest = get_oldest_context(inode, NULL);
+       return !oldest || snapc->seq <= oldest->seq;
+}
+
+/*
+ * We are only allowed to write into/dirty the page if the page is
+ * clean, or already dirty within the same snap context.
+ */
+static int ceph_update_writeable_page(struct file *file,
+                           loff_t pos, unsigned len,
+                           struct page *page)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       loff_t page_off = pos & PAGE_CACHE_MASK;
+       int pos_in_page = pos & ~PAGE_CACHE_MASK;
+       int end_in_page = pos_in_page + len;
+       loff_t i_size;
+       struct ceph_snap_context *snapc;
+       int r;
+
+retry_locked:
+       /* writepages currently holds page lock, but if we change that later, */
+       wait_on_page_writeback(page);
+
+       /* check snap context */
+       BUG_ON(!ci->i_snap_realm);
+       down_read(&mdsc->snap_rwsem);
+       BUG_ON(!ci->i_snap_realm->cached_context);
+       if (page->private &&
+           (void *)page->private != ci->i_snap_realm->cached_context) {
+               /*
+                * this page is already dirty in another (older) snap
+                * context!  is it writeable now?
+                */
+               snapc = get_oldest_context(inode, NULL);
+               up_read(&mdsc->snap_rwsem);
+
+               if (snapc != (void *)page->private) {
+                       dout(" page %p snapc %p not current or oldest\n",
+                            page, (void *)page->private);
+                       /*
+                        * queue for writeback, and wait for snapc to
+                        * be writeable or written
+                        */
+                       snapc = ceph_get_snap_context((void *)page->private);
+                       unlock_page(page);
+                       ceph_queue_writeback(inode);
+                       wait_event_interruptible(ci->i_cap_wq,
+                              context_is_writeable_or_written(inode, snapc));
+                       ceph_put_snap_context(snapc);
+                       return -EAGAIN;
+               }
+
+               /* yay, writeable, do it now (without dropping page lock) */
+               dout(" page %p snapc %p not current, but oldest\n",
+                    page, snapc);
+               if (!clear_page_dirty_for_io(page))
+                       goto retry_locked;
+               r = writepage_nounlock(page, NULL);
+               if (r < 0)
+                       goto fail_nosnap;
+               goto retry_locked;
+       }
+
+       if (PageUptodate(page)) {
+               dout(" page %p already uptodate\n", page);
+               return 0;
+       }
+
+       /* full page? */
+       if (pos_in_page == 0 && len == PAGE_CACHE_SIZE)
+               return 0;
+
+       /* past end of file? */
+       i_size = inode->i_size;   /* caller holds i_mutex */
+
+       if (i_size + len > inode->i_sb->s_maxbytes) {
+               /* file is too big */
+               r = -EINVAL;
+               goto fail;
+       }
+
+       if (page_off >= i_size ||
+           (pos_in_page == 0 && (pos+len) >= i_size &&
+            end_in_page - pos_in_page != PAGE_CACHE_SIZE)) {
+               dout(" zeroing %p 0 - %d and %d - %d\n",
+                    page, pos_in_page, end_in_page, (int)PAGE_CACHE_SIZE);
+               zero_user_segments(page,
+                                  0, pos_in_page,
+                                  end_in_page, PAGE_CACHE_SIZE);
+               return 0;
+       }
+
+       /* we need to read it. */
+       up_read(&mdsc->snap_rwsem);
+       r = readpage_nounlock(file, page);
+       if (r < 0)
+               goto fail_nosnap;
+       goto retry_locked;
+
+fail:
+       up_read(&mdsc->snap_rwsem);
+fail_nosnap:
+       unlock_page(page);
+       return r;
+}
+
+/*
+ * We are only allowed to write into/dirty the page if the page is
+ * clean, or already dirty within the same snap context.
+ */
+static int ceph_write_begin(struct file *file, struct address_space *mapping,
+                           loff_t pos, unsigned len, unsigned flags,
+                           struct page **pagep, void **fsdata)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct page *page;
+       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+       int r;
+
+       do {
+               /* get a page*/
+               page = grab_cache_page_write_begin(mapping, index, 0);
+               if (!page)
+                       return -ENOMEM;
+               *pagep = page;
+
+               dout("write_begin file %p inode %p page %p %d~%d\n", file,
+               inode, page, (int)pos, (int)len);
+
+               r = ceph_update_writeable_page(file, pos, len, page);
+       } while (r == -EAGAIN);
+
+       return r;
+}
+
+/*
+ * we don't do anything in here that simple_write_end doesn't do
+ * except adjust dirty page accounting and drop read lock on
+ * mdsc->snap_rwsem.
+ */
+static int ceph_write_end(struct file *file, struct address_space *mapping,
+                         loff_t pos, unsigned len, unsigned copied,
+                         struct page *page, void *fsdata)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+       int check_cap = 0;
+
+       dout("write_end file %p inode %p page %p %d~%d (%d)\n", file,
+            inode, page, (int)pos, (int)copied, (int)len);
+
+       /* zero the stale part of the page if we did a short copy */
+       if (copied < len)
+               zero_user_segment(page, from+copied, len);
+
+       /* did file size increase? */
+       /* (no need for i_size_read(); we caller holds i_mutex */
+       if (pos+copied > inode->i_size)
+               check_cap = ceph_inode_set_size(inode, pos+copied);
+
+       if (!PageUptodate(page))
+               SetPageUptodate(page);
+
+       set_page_dirty(page);
+
+       unlock_page(page);
+       up_read(&mdsc->snap_rwsem);
+       page_cache_release(page);
+
+       if (check_cap)
+               ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL);
+
+       return copied;
+}
+
+/*
+ * we set .direct_IO to indicate direct io is supported, but since we
+ * intercept O_DIRECT reads and writes early, this function should
+ * never get called.
+ */
+static ssize_t ceph_direct_io(int rw, struct kiocb *iocb,
+                             const struct iovec *iov,
+                             loff_t pos, unsigned long nr_segs)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+const struct address_space_operations ceph_aops = {
+       .readpage = ceph_readpage,
+       .readpages = ceph_readpages,
+       .writepage = ceph_writepage,
+       .writepages = ceph_writepages_start,
+       .write_begin = ceph_write_begin,
+       .write_end = ceph_write_end,
+       .set_page_dirty = ceph_set_page_dirty,
+       .invalidatepage = ceph_invalidatepage,
+       .releasepage = ceph_releasepage,
+       .direct_IO = ceph_direct_io,
+};
+
+
+/*
+ * vm ops
+ */
+
+/*
+ * Reuse write_begin here for simplicity.
+ */
+static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct inode *inode = vma->vm_file->f_dentry->d_inode;
+       struct page *page = vmf->page;
+       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       loff_t off = page->index << PAGE_CACHE_SHIFT;
+       loff_t size, len;
+       int ret;
+
+       size = i_size_read(inode);
+       if (off + PAGE_CACHE_SIZE <= size)
+               len = PAGE_CACHE_SIZE;
+       else
+               len = size & ~PAGE_CACHE_MASK;
+
+       dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode,
+            off, len, page, page->index);
+
+       lock_page(page);
+
+       ret = VM_FAULT_NOPAGE;
+       if ((off > size) ||
+           (page->mapping != inode->i_mapping))
+               goto out;
+
+       ret = ceph_update_writeable_page(vma->vm_file, off, len, page);
+       if (ret == 0) {
+               /* success.  we'll keep the page locked. */
+               set_page_dirty(page);
+               up_read(&mdsc->snap_rwsem);
+               ret = VM_FAULT_LOCKED;
+       } else {
+               if (ret == -ENOMEM)
+                       ret = VM_FAULT_OOM;
+               else
+                       ret = VM_FAULT_SIGBUS;
+       }
+out:
+       dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret);
+       if (ret != VM_FAULT_LOCKED)
+               unlock_page(page);
+       return ret;
+}
+
+static struct vm_operations_struct ceph_vmops = {
+       .fault          = filemap_fault,
+       .page_mkwrite   = ceph_page_mkwrite,
+};
+
+int ceph_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct address_space *mapping = file->f_mapping;
+
+       if (!mapping->a_ops->readpage)
+               return -ENOEXEC;
+       file_accessed(file);
+       vma->vm_ops = &ceph_vmops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
+       return 0;
+}
diff --git a/fs/ceph/armor.c b/fs/ceph/armor.c
new file mode 100644 (file)
index 0000000..67b2c03
--- /dev/null
@@ -0,0 +1,99 @@
+
+#include <linux/errno.h>
+
+/*
+ * base64 encode/decode.
+ */
+
+const char *pem_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int encode_bits(int c)
+{
+       return pem_key[c];
+}
+
+static int decode_bits(char c)
+{
+       if (c >= 'A' && c <= 'Z')
+               return c - 'A';
+       if (c >= 'a' && c <= 'z')
+               return c - 'a' + 26;
+       if (c >= '0' && c <= '9')
+               return c - '0' + 52;
+       if (c == '+')
+               return 62;
+       if (c == '/')
+               return 63;
+       if (c == '=')
+               return 0; /* just non-negative, please */
+       return -EINVAL;
+}
+
+int ceph_armor(char *dst, const char *src, const char *end)
+{
+       int olen = 0;
+       int line = 0;
+
+       while (src < end) {
+               unsigned char a, b, c;
+
+               a = *src++;
+               *dst++ = encode_bits(a >> 2);
+               if (src < end) {
+                       b = *src++;
+                       *dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
+                       if (src < end) {
+                               c = *src++;
+                               *dst++ = encode_bits(((b & 15) << 2) |
+                                                    (c >> 6));
+                               *dst++ = encode_bits(c & 63);
+                       } else {
+                               *dst++ = encode_bits((b & 15) << 2);
+                               *dst++ = '=';
+                       }
+               } else {
+                       *dst++ = encode_bits(((a & 3) << 4));
+                       *dst++ = '=';
+                       *dst++ = '=';
+               }
+               olen += 4;
+               line += 4;
+               if (line == 64) {
+                       line = 0;
+                       *(dst++) = '\n';
+                       olen++;
+               }
+       }
+       return olen;
+}
+
+int ceph_unarmor(char *dst, const char *src, const char *end)
+{
+       int olen = 0;
+
+       while (src < end) {
+               int a, b, c, d;
+
+               if (src < end && src[0] == '\n')
+                       src++;
+               if (src + 4 > end)
+                       return -EINVAL;
+               a = decode_bits(src[0]);
+               b = decode_bits(src[1]);
+               c = decode_bits(src[2]);
+               d = decode_bits(src[3]);
+               if (a < 0 || b < 0 || c < 0 || d < 0)
+                       return -EINVAL;
+
+               *dst++ = (a << 2) | (b >> 4);
+               if (src[2] == '=')
+                       return olen + 1;
+               *dst++ = ((b & 15) << 4) | (c >> 2);
+               if (src[3] == '=')
+                       return olen + 2;
+               *dst++ = ((c & 3) << 6) | d;
+               olen += 3;
+               src += 4;
+       }
+       return olen;
+}
diff --git a/fs/ceph/auth.c b/fs/ceph/auth.c
new file mode 100644 (file)
index 0000000..abb204f
--- /dev/null
@@ -0,0 +1,257 @@
+#include "ceph_debug.h"
+
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include "types.h"
+#include "auth_none.h"
+#include "auth_x.h"
+#include "decode.h"
+#include "super.h"
+
+#include "messenger.h"
+
+/*
+ * get protocol handler
+ */
+static u32 supported_protocols[] = {
+       CEPH_AUTH_NONE,
+       CEPH_AUTH_CEPHX
+};
+
+int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
+{
+       switch (protocol) {
+       case CEPH_AUTH_NONE:
+               return ceph_auth_none_init(ac);
+       case CEPH_AUTH_CEPHX:
+               return ceph_x_init(ac);
+       default:
+               return -ENOENT;
+       }
+}
+
+/*
+ * setup, teardown.
+ */
+struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
+{
+       struct ceph_auth_client *ac;
+       int ret;
+
+       dout("auth_init name '%s' secret '%s'\n", name, secret);
+
+       ret = -ENOMEM;
+       ac = kzalloc(sizeof(*ac), GFP_NOFS);
+       if (!ac)
+               goto out;
+
+       ac->negotiating = true;
+       if (name)
+               ac->name = name;
+       else
+               ac->name = CEPH_AUTH_NAME_DEFAULT;
+       dout("auth_init name %s secret %s\n", ac->name, secret);
+       ac->secret = secret;
+       return ac;
+
+out:
+       return ERR_PTR(ret);
+}
+
+void ceph_auth_destroy(struct ceph_auth_client *ac)
+{
+       dout("auth_destroy %p\n", ac);
+       if (ac->ops)
+               ac->ops->destroy(ac);
+       kfree(ac);
+}
+
+/*
+ * Reset occurs when reconnecting to the monitor.
+ */
+void ceph_auth_reset(struct ceph_auth_client *ac)
+{
+       dout("auth_reset %p\n", ac);
+       if (ac->ops && !ac->negotiating)
+               ac->ops->reset(ac);
+       ac->negotiating = true;
+}
+
+int ceph_entity_name_encode(const char *name, void **p, void *end)
+{
+       int len = strlen(name);
+
+       if (*p + 2*sizeof(u32) + len > end)
+               return -ERANGE;
+       ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
+       ceph_encode_32(p, len);
+       ceph_encode_copy(p, name, len);
+       return 0;
+}
+
+/*
+ * Initiate protocol negotiation with monitor.  Include entity name
+ * and list supported protocols.
+ */
+int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
+{
+       struct ceph_mon_request_header *monhdr = buf;
+       void *p = monhdr + 1, *end = buf + len, *lenp;
+       int i, num;
+       int ret;
+
+       dout("auth_build_hello\n");
+       monhdr->have_version = 0;
+       monhdr->session_mon = cpu_to_le16(-1);
+       monhdr->session_mon_tid = 0;
+
+       ceph_encode_32(&p, 0);  /* no protocol, yet */
+
+       lenp = p;
+       p += sizeof(u32);
+
+       ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
+       ceph_encode_8(&p, 1);
+       num = ARRAY_SIZE(supported_protocols);
+       ceph_encode_32(&p, num);
+       ceph_decode_need(&p, end, num * sizeof(u32), bad);
+       for (i = 0; i < num; i++)
+               ceph_encode_32(&p, supported_protocols[i]);
+
+       ret = ceph_entity_name_encode(ac->name, &p, end);
+       if (ret < 0)
+               return ret;
+       ceph_decode_need(&p, end, sizeof(u64), bad);
+       ceph_encode_64(&p, ac->global_id);
+
+       ceph_encode_32(&lenp, p - lenp - sizeof(u32));
+       return p - buf;
+
+bad:
+       return -ERANGE;
+}
+
+int ceph_build_auth_request(struct ceph_auth_client *ac,
+                          void *msg_buf, size_t msg_len)
+{
+       struct ceph_mon_request_header *monhdr = msg_buf;
+       void *p = monhdr + 1;
+       void *end = msg_buf + msg_len;
+       int ret;
+
+       monhdr->have_version = 0;
+       monhdr->session_mon = cpu_to_le16(-1);
+       monhdr->session_mon_tid = 0;
+
+       ceph_encode_32(&p, ac->protocol);
+
+       ret = ac->ops->build_request(ac, p + sizeof(u32), end);
+       if (ret < 0) {
+               pr_err("error %d building request\n", ret);
+               return ret;
+       }
+       dout(" built request %d bytes\n", ret);
+       ceph_encode_32(&p, ret);
+       return p + ret - msg_buf;
+}
+
+/*
+ * Handle auth message from monitor.
+ */
+int ceph_handle_auth_reply(struct ceph_auth_client *ac,
+                          void *buf, size_t len,
+                          void *reply_buf, size_t reply_len)
+{
+       void *p = buf;
+       void *end = buf + len;
+       int protocol;
+       s32 result;
+       u64 global_id;
+       void *payload, *payload_end;
+       int payload_len;
+       char *result_msg;
+       int result_msg_len;
+       int ret = -EINVAL;
+
+       dout("handle_auth_reply %p %p\n", p, end);
+       ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
+       protocol = ceph_decode_32(&p);
+       result = ceph_decode_32(&p);
+       global_id = ceph_decode_64(&p);
+       payload_len = ceph_decode_32(&p);
+       payload = p;
+       p += payload_len;
+       ceph_decode_need(&p, end, sizeof(u32), bad);
+       result_msg_len = ceph_decode_32(&p);
+       result_msg = p;
+       p += result_msg_len;
+       if (p != end)
+               goto bad;
+
+       dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
+            result_msg, global_id, payload_len);
+
+       payload_end = payload + payload_len;
+
+       if (global_id && ac->global_id != global_id) {
+               dout(" set global_id %lld -> %lld\n", ac->global_id, global_id);
+               ac->global_id = global_id;
+       }
+
+       if (ac->negotiating) {
+               /* server does not support our protocols? */
+               if (!protocol && result < 0) {
+                       ret = result;
+                       goto out;
+               }
+               /* set up (new) protocol handler? */
+               if (ac->protocol && ac->protocol != protocol) {
+                       ac->ops->destroy(ac);
+                       ac->protocol = 0;
+                       ac->ops = NULL;
+               }
+               if (ac->protocol != protocol) {
+                       ret = ceph_auth_init_protocol(ac, protocol);
+                       if (ret) {
+                               pr_err("error %d on auth protocol %d init\n",
+                                      ret, protocol);
+                               goto out;
+                       }
+               }
+
+               ac->negotiating = false;
+       }
+
+       ret = ac->ops->handle_reply(ac, result, payload, payload_end);
+       if (ret == -EAGAIN) {
+               return ceph_build_auth_request(ac, reply_buf, reply_len);
+       } else if (ret) {
+               pr_err("authentication error %d\n", ret);
+               return ret;
+       }
+       return 0;
+
+bad:
+       pr_err("failed to decode auth msg\n");
+out:
+       return ret;
+}
+
+int ceph_build_auth(struct ceph_auth_client *ac,
+                   void *msg_buf, size_t msg_len)
+{
+       if (!ac->protocol)
+               return ceph_auth_build_hello(ac, msg_buf, msg_len);
+       BUG_ON(!ac->ops);
+       if (!ac->ops->is_authenticated(ac))
+               return ceph_build_auth_request(ac, msg_buf, msg_len);
+       return 0;
+}
+
+int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
+{
+       if (!ac->ops)
+               return 0;
+       return ac->ops->is_authenticated(ac);
+}
diff --git a/fs/ceph/auth.h b/fs/ceph/auth.h
new file mode 100644 (file)
index 0000000..ca4f57c
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _FS_CEPH_AUTH_H
+#define _FS_CEPH_AUTH_H
+
+#include "types.h"
+#include "buffer.h"
+
+/*
+ * Abstract interface for communicating with the authenticate module.
+ * There is some handshake that takes place between us and the monitor
+ * to acquire the necessary keys.  These are used to generate an
+ * 'authorizer' that we use when connecting to a service (mds, osd).
+ */
+
+struct ceph_auth_client;
+struct ceph_authorizer;
+
+struct ceph_auth_client_ops {
+       /*
+        * true if we are authenticated and can connect to
+        * services.
+        */
+       int (*is_authenticated)(struct ceph_auth_client *ac);
+
+       /*
+        * build requests and process replies during monitor
+        * handshake.  if handle_reply returns -EAGAIN, we build
+        * another request.
+        */
+       int (*build_request)(struct ceph_auth_client *ac, void *buf, void *end);
+       int (*handle_reply)(struct ceph_auth_client *ac, int result,
+                           void *buf, void *end);
+
+       /*
+        * Create authorizer for connecting to a service, and verify
+        * the response to authenticate the service.
+        */
+       int (*create_authorizer)(struct ceph_auth_client *ac, int peer_type,
+                                struct ceph_authorizer **a,
+                                void **buf, size_t *len,
+                                void **reply_buf, size_t *reply_len);
+       int (*verify_authorizer_reply)(struct ceph_auth_client *ac,
+                                      struct ceph_authorizer *a, size_t len);
+       void (*destroy_authorizer)(struct ceph_auth_client *ac,
+                                  struct ceph_authorizer *a);
+       void (*invalidate_authorizer)(struct ceph_auth_client *ac,
+                                     int peer_type);
+
+       /* reset when we (re)connect to a monitor */
+       void (*reset)(struct ceph_auth_client *ac);
+
+       void (*destroy)(struct ceph_auth_client *ac);
+};
+
+struct ceph_auth_client {
+       u32 protocol;           /* CEPH_AUTH_* */
+       void *private;          /* for use by protocol implementation */
+       const struct ceph_auth_client_ops *ops;  /* null iff protocol==0 */
+
+       bool negotiating;       /* true if negotiating protocol */
+       const char *name;       /* entity name */
+       u64 global_id;          /* our unique id in system */
+       const char *secret;     /* our secret key */
+       unsigned want_keys;     /* which services we want */
+};
+
+extern struct ceph_auth_client *ceph_auth_init(const char *name,
+                                              const char *secret);
+extern void ceph_auth_destroy(struct ceph_auth_client *ac);
+
+extern void ceph_auth_reset(struct ceph_auth_client *ac);
+
+extern int ceph_auth_build_hello(struct ceph_auth_client *ac,
+                                void *buf, size_t len);
+extern int ceph_handle_auth_reply(struct ceph_auth_client *ac,
+                                 void *buf, size_t len,
+                                 void *reply_buf, size_t reply_len);
+extern int ceph_entity_name_encode(const char *name, void **p, void *end);
+
+extern int ceph_build_auth(struct ceph_auth_client *ac,
+                   void *msg_buf, size_t msg_len);
+
+extern int ceph_auth_is_authenticated(struct ceph_auth_client *ac);
+
+#endif
diff --git a/fs/ceph/auth_none.c b/fs/ceph/auth_none.c
new file mode 100644 (file)
index 0000000..b4ef6f0
--- /dev/null
@@ -0,0 +1,121 @@
+
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/random.h>
+
+#include "auth_none.h"
+#include "auth.h"
+#include "decode.h"
+
+static void reset(struct ceph_auth_client *ac)
+{
+       struct ceph_auth_none_info *xi = ac->private;
+
+       xi->starting = true;
+       xi->built_authorizer = false;
+}
+
+static void destroy(struct ceph_auth_client *ac)
+{
+       kfree(ac->private);
+       ac->private = NULL;
+}
+
+static int is_authenticated(struct ceph_auth_client *ac)
+{
+       struct ceph_auth_none_info *xi = ac->private;
+
+       return !xi->starting;
+}
+
+/*
+ * the generic auth code decode the global_id, and we carry no actual
+ * authenticate state, so nothing happens here.
+ */
+static int handle_reply(struct ceph_auth_client *ac, int result,
+                       void *buf, void *end)
+{
+       struct ceph_auth_none_info *xi = ac->private;
+
+       xi->starting = false;
+       return result;
+}
+
+/*
+ * build an 'authorizer' with our entity_name and global_id.  we can
+ * reuse a single static copy since it is identical for all services
+ * we connect to.
+ */
+static int ceph_auth_none_create_authorizer(
+       struct ceph_auth_client *ac, int peer_type,
+       struct ceph_authorizer **a,
+       void **buf, size_t *len,
+       void **reply_buf, size_t *reply_len)
+{
+       struct ceph_auth_none_info *ai = ac->private;
+       struct ceph_none_authorizer *au = &ai->au;
+       void *p, *end;
+       int ret;
+
+       if (!ai->built_authorizer) {
+               p = au->buf;
+               end = p + sizeof(au->buf);
+               ceph_encode_8(&p, 1);
+               ret = ceph_entity_name_encode(ac->name, &p, end - 8);
+               if (ret < 0)
+                       goto bad;
+               ceph_decode_need(&p, end, sizeof(u64), bad2);
+               ceph_encode_64(&p, ac->global_id);
+               au->buf_len = p - (void *)au->buf;
+               ai->built_authorizer = true;
+               dout("built authorizer len %d\n", au->buf_len);
+       }
+
+       *a = (struct ceph_authorizer *)au;
+       *buf = au->buf;
+       *len = au->buf_len;
+       *reply_buf = au->reply_buf;
+       *reply_len = sizeof(au->reply_buf);
+       return 0;
+
+bad2:
+       ret = -ERANGE;
+bad:
+       return ret;
+}
+
+static void ceph_auth_none_destroy_authorizer(struct ceph_auth_client *ac,
+                                     struct ceph_authorizer *a)
+{
+       /* nothing to do */
+}
+
+static const struct ceph_auth_client_ops ceph_auth_none_ops = {
+       .reset = reset,
+       .destroy = destroy,
+       .is_authenticated = is_authenticated,
+       .handle_reply = handle_reply,
+       .create_authorizer = ceph_auth_none_create_authorizer,
+       .destroy_authorizer = ceph_auth_none_destroy_authorizer,
+};
+
+int ceph_auth_none_init(struct ceph_auth_client *ac)
+{
+       struct ceph_auth_none_info *xi;
+
+       dout("ceph_auth_none_init %p\n", ac);
+       xi = kzalloc(sizeof(*xi), GFP_NOFS);
+       if (!xi)
+               return -ENOMEM;
+
+       xi->starting = true;
+       xi->built_authorizer = false;
+
+       ac->protocol = CEPH_AUTH_NONE;
+       ac->private = xi;
+       ac->ops = &ceph_auth_none_ops;
+       return 0;
+}
+
diff --git a/fs/ceph/auth_none.h b/fs/ceph/auth_none.h
new file mode 100644 (file)
index 0000000..56c0553
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _FS_CEPH_AUTH_NONE_H
+#define _FS_CEPH_AUTH_NONE_H
+
+#include "auth.h"
+
+/*
+ * null security mode.
+ *
+ * we use a single static authorizer that simply encodes our entity name
+ * and global id.
+ */
+
+struct ceph_none_authorizer {
+       char buf[128];
+       int buf_len;
+       char reply_buf[0];
+};
+
+struct ceph_auth_none_info {
+       bool starting;
+       bool built_authorizer;
+       struct ceph_none_authorizer au;   /* we only need one; it's static */
+};
+
+extern int ceph_auth_none_init(struct ceph_auth_client *ac);
+
+#endif
+
diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c
new file mode 100644 (file)
index 0000000..f031842
--- /dev/null
@@ -0,0 +1,656 @@
+
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/random.h>
+
+#include "auth_x.h"
+#include "auth_x_protocol.h"
+#include "crypto.h"
+#include "auth.h"
+#include "decode.h"
+
+struct kmem_cache *ceph_x_ticketbuf_cachep;
+
+#define TEMP_TICKET_BUF_LEN    256
+
+static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
+
+static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi = ac->private;
+       int need;
+
+       ceph_x_validate_tickets(ac, &need);
+       dout("ceph_x_is_authenticated want=%d need=%d have=%d\n",
+            ac->want_keys, need, xi->have_keys);
+       return (ac->want_keys & xi->have_keys) == ac->want_keys;
+}
+
+static int ceph_x_encrypt(struct ceph_crypto_key *secret,
+                         void *ibuf, int ilen, void *obuf, size_t olen)
+{
+       struct ceph_x_encrypt_header head = {
+               .struct_v = 1,
+               .magic = cpu_to_le64(CEPHX_ENC_MAGIC)
+       };
+       size_t len = olen - sizeof(u32);
+       int ret;
+
+       ret = ceph_encrypt2(secret, obuf + sizeof(u32), &len,
+                           &head, sizeof(head), ibuf, ilen);
+       if (ret)
+               return ret;
+       ceph_encode_32(&obuf, len);
+       return len + sizeof(u32);
+}
+
+static int ceph_x_decrypt(struct ceph_crypto_key *secret,
+                         void **p, void *end, void *obuf, size_t olen)
+{
+       struct ceph_x_encrypt_header head;
+       size_t head_len = sizeof(head);
+       int len, ret;
+
+       len = ceph_decode_32(p);
+       if (*p + len > end)
+               return -EINVAL;
+
+       dout("ceph_x_decrypt len %d\n", len);
+       ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen,
+                           *p, len);
+       if (ret)
+               return ret;
+       if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC)
+               return -EPERM;
+       *p += len;
+       return olen;
+}
+
+/*
+ * get existing (or insert new) ticket handler
+ */
+struct ceph_x_ticket_handler *get_ticket_handler(struct ceph_auth_client *ac,
+                                                int service)
+{
+       struct ceph_x_ticket_handler *th;
+       struct ceph_x_info *xi = ac->private;
+       struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node;
+
+       while (*p) {
+               parent = *p;
+               th = rb_entry(parent, struct ceph_x_ticket_handler, node);
+               if (service < th->service)
+                       p = &(*p)->rb_left;
+               else if (service > th->service)
+                       p = &(*p)->rb_right;
+               else
+                       return th;
+       }
+
+       /* add it */
+       th = kzalloc(sizeof(*th), GFP_NOFS);
+       if (!th)
+               return ERR_PTR(-ENOMEM);
+       th->service = service;
+       rb_link_node(&th->node, parent, p);
+       rb_insert_color(&th->node, &xi->ticket_handlers);
+       return th;
+}
+
+static void remove_ticket_handler(struct ceph_auth_client *ac,
+                                 struct ceph_x_ticket_handler *th)
+{
+       struct ceph_x_info *xi = ac->private;
+
+       dout("remove_ticket_handler %p %d\n", th, th->service);
+       rb_erase(&th->node, &xi->ticket_handlers);
+       ceph_crypto_key_destroy(&th->session_key);
+       if (th->ticket_blob)
+               ceph_buffer_put(th->ticket_blob);
+       kfree(th);
+}
+
+static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
+                                   struct ceph_crypto_key *secret,
+                                   void *buf, void *end)
+{
+       struct ceph_x_info *xi = ac->private;
+       int num;
+       void *p = buf;
+       int ret;
+       char *dbuf;
+       char *ticket_buf;
+       u8 struct_v;
+
+       dbuf = kmem_cache_alloc(ceph_x_ticketbuf_cachep, GFP_NOFS | GFP_ATOMIC);
+       if (!dbuf)
+               return -ENOMEM;
+
+       ret = -ENOMEM;
+       ticket_buf = kmem_cache_alloc(ceph_x_ticketbuf_cachep,
+                                     GFP_NOFS | GFP_ATOMIC);
+       if (!ticket_buf)
+               goto out_dbuf;
+
+       ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
+       struct_v = ceph_decode_8(&p);
+       if (struct_v != 1)
+               goto bad;
+       num = ceph_decode_32(&p);
+       dout("%d tickets\n", num);
+       while (num--) {
+               int type;
+               u8 struct_v;
+               struct ceph_x_ticket_handler *th;
+               void *dp, *dend;
+               int dlen;
+               char is_enc;
+               struct timespec validity;
+               struct ceph_crypto_key old_key;
+               void *tp, *tpend;
+
+               ceph_decode_need(&p, end, sizeof(u32) + 1, bad);
+
+               type = ceph_decode_32(&p);
+               dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
+
+               struct_v = ceph_decode_8(&p);
+               if (struct_v != 1)
+                       goto bad;
+
+               th = get_ticket_handler(ac, type);
+               if (IS_ERR(th)) {
+                       ret = PTR_ERR(th);
+                       goto out;
+               }
+
+               /* blob for me */
+               dlen = ceph_x_decrypt(secret, &p, end, dbuf,
+                                     TEMP_TICKET_BUF_LEN);
+               if (dlen <= 0) {
+                       ret = dlen;
+                       goto out;
+               }
+               dout(" decrypted %d bytes\n", dlen);
+               dend = dbuf + dlen;
+               dp = dbuf;
+
+               struct_v = ceph_decode_8(&dp);
+               if (struct_v != 1)
+                       goto bad;
+
+               memcpy(&old_key, &th->session_key, sizeof(old_key));
+               ret = ceph_crypto_key_decode(&th->session_key, &dp, dend);
+               if (ret)
+                       goto out;
+
+               ceph_decode_copy(&dp, &th->validity, sizeof(th->validity));
+               ceph_decode_timespec(&validity, &th->validity);
+               th->expires = get_seconds() + validity.tv_sec;
+               th->renew_after = th->expires - (validity.tv_sec / 4);
+               dout(" expires=%lu renew_after=%lu\n", th->expires,
+                    th->renew_after);
+
+               /* ticket blob for service */
+               ceph_decode_8_safe(&p, end, is_enc, bad);
+               tp = ticket_buf;
+               if (is_enc) {
+                       /* encrypted */
+                       dout(" encrypted ticket\n");
+                       dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf,
+                                             TEMP_TICKET_BUF_LEN);
+                       if (dlen < 0) {
+                               ret = dlen;
+                               goto out;
+                       }
+                       dlen = ceph_decode_32(&tp);
+               } else {
+                       /* unencrypted */
+                       ceph_decode_32_safe(&p, end, dlen, bad);
+                       ceph_decode_need(&p, end, dlen, bad);
+                       ceph_decode_copy(&p, ticket_buf, dlen);
+               }
+               tpend = tp + dlen;
+               dout(" ticket blob is %d bytes\n", dlen);
+               ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
+               struct_v = ceph_decode_8(&tp);
+               th->secret_id = ceph_decode_64(&tp);
+               ret = ceph_decode_buffer(&th->ticket_blob, &tp, tpend);
+               if (ret)
+                       goto out;
+               dout(" got ticket service %d (%s) secret_id %lld len %d\n",
+                    type, ceph_entity_type_name(type), th->secret_id,
+                    (int)th->ticket_blob->vec.iov_len);
+               xi->have_keys |= th->service;
+       }
+
+       ret = 0;
+out:
+       kmem_cache_free(ceph_x_ticketbuf_cachep, ticket_buf);
+out_dbuf:
+       kmem_cache_free(ceph_x_ticketbuf_cachep, dbuf);
+       return ret;
+
+bad:
+       ret = -EINVAL;
+       goto out;
+}
+
+static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
+                                  struct ceph_x_ticket_handler *th,
+                                  struct ceph_x_authorizer *au)
+{
+       int len;
+       struct ceph_x_authorize_a *msg_a;
+       struct ceph_x_authorize_b msg_b;
+       void *p, *end;
+       int ret;
+       int ticket_blob_len =
+               (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0);
+
+       dout("build_authorizer for %s %p\n",
+            ceph_entity_type_name(th->service), au);
+
+       len = sizeof(*msg_a) + sizeof(msg_b) + sizeof(u32) +
+               ticket_blob_len + 16;
+       dout("  need len %d\n", len);
+       if (au->buf && au->buf->alloc_len < len) {
+               ceph_buffer_put(au->buf);
+               au->buf = NULL;
+       }
+       if (!au->buf) {
+               au->buf = ceph_buffer_new(len, GFP_NOFS);
+               if (!au->buf)
+                       return -ENOMEM;
+       }
+       au->service = th->service;
+
+       msg_a = au->buf->vec.iov_base;
+       msg_a->struct_v = 1;
+       msg_a->global_id = cpu_to_le64(ac->global_id);
+       msg_a->service_id = cpu_to_le32(th->service);
+       msg_a->ticket_blob.struct_v = 1;
+       msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id);
+       msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len);
+       if (ticket_blob_len) {
+               memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base,
+                      th->ticket_blob->vec.iov_len);
+       }
+       dout(" th %p secret_id %lld %lld\n", th, th->secret_id,
+            le64_to_cpu(msg_a->ticket_blob.secret_id));
+
+       p = msg_a + 1;
+       p += ticket_blob_len;
+       end = au->buf->vec.iov_base + au->buf->vec.iov_len;
+
+       get_random_bytes(&au->nonce, sizeof(au->nonce));
+       msg_b.struct_v = 1;
+       msg_b.nonce = cpu_to_le64(au->nonce);
+       ret = ceph_x_encrypt(&th->session_key, &msg_b, sizeof(msg_b),
+                            p, end - p);
+       if (ret < 0)
+               goto out_buf;
+       p += ret;
+       au->buf->vec.iov_len = p - au->buf->vec.iov_base;
+       dout(" built authorizer nonce %llx len %d\n", au->nonce,
+            (int)au->buf->vec.iov_len);
+       return 0;
+
+out_buf:
+       ceph_buffer_put(au->buf);
+       au->buf = NULL;
+       return ret;
+}
+
+static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th,
+                               void **p, void *end)
+{
+       ceph_decode_need(p, end, 1 + sizeof(u64), bad);
+       ceph_encode_8(p, 1);
+       ceph_encode_64(p, th->secret_id);
+       if (th->ticket_blob) {
+               const char *buf = th->ticket_blob->vec.iov_base;
+               u32 len = th->ticket_blob->vec.iov_len;
+
+               ceph_encode_32_safe(p, end, len, bad);
+               ceph_encode_copy_safe(p, end, buf, len, bad);
+       } else {
+               ceph_encode_32_safe(p, end, 0, bad);
+       }
+
+       return 0;
+bad:
+       return -ERANGE;
+}
+
+static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed)
+{
+       int want = ac->want_keys;
+       struct ceph_x_info *xi = ac->private;
+       int service;
+
+       *pneed = ac->want_keys & ~(xi->have_keys);
+
+       for (service = 1; service <= want; service <<= 1) {
+               struct ceph_x_ticket_handler *th;
+
+               if (!(ac->want_keys & service))
+                       continue;
+
+               if (*pneed & service)
+                       continue;
+
+               th = get_ticket_handler(ac, service);
+
+               if (!th) {
+                       *pneed |= service;
+                       continue;
+               }
+
+               if (get_seconds() >= th->renew_after)
+                       *pneed |= service;
+               if (get_seconds() >= th->expires)
+                       xi->have_keys &= ~service;
+       }
+}
+
+
+static int ceph_x_build_request(struct ceph_auth_client *ac,
+                               void *buf, void *end)
+{
+       struct ceph_x_info *xi = ac->private;
+       int need;
+       struct ceph_x_request_header *head = buf;
+       int ret;
+       struct ceph_x_ticket_handler *th =
+               get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
+
+       ceph_x_validate_tickets(ac, &need);
+
+       dout("build_request want %x have %x need %x\n",
+            ac->want_keys, xi->have_keys, need);
+
+       if (need & CEPH_ENTITY_TYPE_AUTH) {
+               struct ceph_x_authenticate *auth = (void *)(head + 1);
+               void *p = auth + 1;
+               struct ceph_x_challenge_blob tmp;
+               char tmp_enc[40];
+               u64 *u;
+
+               if (p > end)
+                       return -ERANGE;
+
+               dout(" get_auth_session_key\n");
+               head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY);
+
+               /* encrypt and hash */
+               get_random_bytes(&auth->client_challenge, sizeof(u64));
+               tmp.client_challenge = auth->client_challenge;
+               tmp.server_challenge = cpu_to_le64(xi->server_challenge);
+               ret = ceph_x_encrypt(&xi->secret, &tmp, sizeof(tmp),
+                                    tmp_enc, sizeof(tmp_enc));
+               if (ret < 0)
+                       return ret;
+
+               auth->struct_v = 1;
+               auth->key = 0;
+               for (u = (u64 *)tmp_enc; u + 1 <= (u64 *)(tmp_enc + ret); u++)
+                       auth->key ^= *u;
+               dout(" server_challenge %llx client_challenge %llx key %llx\n",
+                    xi->server_challenge, le64_to_cpu(auth->client_challenge),
+                    le64_to_cpu(auth->key));
+
+               /* now encode the old ticket if exists */
+               ret = ceph_x_encode_ticket(th, &p, end);
+               if (ret < 0)
+                       return ret;
+
+               return p - buf;
+       }
+
+       if (need) {
+               void *p = head + 1;
+               struct ceph_x_service_ticket_request *req;
+
+               if (p > end)
+                       return -ERANGE;
+               head->op = cpu_to_le16(CEPHX_GET_PRINCIPAL_SESSION_KEY);
+
+               BUG_ON(!th);
+               ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer);
+               if (ret)
+                       return ret;
+               ceph_encode_copy(&p, xi->auth_authorizer.buf->vec.iov_base,
+                                xi->auth_authorizer.buf->vec.iov_len);
+
+               req = p;
+               req->keys = cpu_to_le32(need);
+               p += sizeof(*req);
+               return p - buf;
+       }
+
+       return 0;
+}
+
+static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
+                              void *buf, void *end)
+{
+       struct ceph_x_info *xi = ac->private;
+       struct ceph_x_reply_header *head = buf;
+       struct ceph_x_ticket_handler *th;
+       int len = end - buf;
+       int op;
+       int ret;
+
+       if (result)
+               return result;  /* XXX hmm? */
+
+       if (xi->starting) {
+               /* it's a hello */
+               struct ceph_x_server_challenge *sc = buf;
+
+               if (len != sizeof(*sc))
+                       return -EINVAL;
+               xi->server_challenge = le64_to_cpu(sc->server_challenge);
+               dout("handle_reply got server challenge %llx\n",
+                    xi->server_challenge);
+               xi->starting = false;
+               xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH;
+               return -EAGAIN;
+       }
+
+       op = le32_to_cpu(head->op);
+       result = le32_to_cpu(head->result);
+       dout("handle_reply op %d result %d\n", op, result);
+       switch (op) {
+       case CEPHX_GET_AUTH_SESSION_KEY:
+               /* verify auth key */
+               ret = ceph_x_proc_ticket_reply(ac, &xi->secret,
+                                              buf + sizeof(*head), end);
+               break;
+
+       case CEPHX_GET_PRINCIPAL_SESSION_KEY:
+               th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
+               BUG_ON(!th);
+               ret = ceph_x_proc_ticket_reply(ac, &th->session_key,
+                                              buf + sizeof(*head), end);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       if (ret)
+               return ret;
+       if (ac->want_keys == xi->have_keys)
+               return 0;
+       return -EAGAIN;
+}
+
+static int ceph_x_create_authorizer(
+       struct ceph_auth_client *ac, int peer_type,
+       struct ceph_authorizer **a,
+       void **buf, size_t *len,
+       void **reply_buf, size_t *reply_len)
+{
+       struct ceph_x_authorizer *au;
+       struct ceph_x_ticket_handler *th;
+       int ret;
+
+       th = get_ticket_handler(ac, peer_type);
+       if (IS_ERR(th))
+               return PTR_ERR(th);
+
+       au = kzalloc(sizeof(*au), GFP_NOFS);
+       if (!au)
+               return -ENOMEM;
+
+       ret = ceph_x_build_authorizer(ac, th, au);
+       if (ret) {
+               kfree(au);
+               return ret;
+       }
+
+       *a = (struct ceph_authorizer *)au;
+       *buf = au->buf->vec.iov_base;
+       *len = au->buf->vec.iov_len;
+       *reply_buf = au->reply_buf;
+       *reply_len = sizeof(au->reply_buf);
+       return 0;
+}
+
+static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
+                                         struct ceph_authorizer *a, size_t len)
+{
+       struct ceph_x_authorizer *au = (void *)a;
+       struct ceph_x_ticket_handler *th;
+       int ret = 0;
+       struct ceph_x_authorize_reply reply;
+       void *p = au->reply_buf;
+       void *end = p + sizeof(au->reply_buf);
+
+       th = get_ticket_handler(ac, au->service);
+       if (!th)
+               return -EIO;  /* hrm! */
+       ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply));
+       if (ret < 0)
+               return ret;
+       if (ret != sizeof(reply))
+               return -EPERM;
+
+       if (au->nonce + 1 != le64_to_cpu(reply.nonce_plus_one))
+               ret = -EPERM;
+       else
+               ret = 0;
+       dout("verify_authorizer_reply nonce %llx got %llx ret %d\n",
+            au->nonce, le64_to_cpu(reply.nonce_plus_one), ret);
+       return ret;
+}
+
+static void ceph_x_destroy_authorizer(struct ceph_auth_client *ac,
+                                     struct ceph_authorizer *a)
+{
+       struct ceph_x_authorizer *au = (void *)a;
+
+       ceph_buffer_put(au->buf);
+       kfree(au);
+}
+
+
+static void ceph_x_reset(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi = ac->private;
+
+       dout("reset\n");
+       xi->starting = true;
+       xi->server_challenge = 0;
+}
+
+static void ceph_x_destroy(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi = ac->private;
+       struct rb_node *p;
+
+       dout("ceph_x_destroy %p\n", ac);
+       ceph_crypto_key_destroy(&xi->secret);
+
+       while ((p = rb_first(&xi->ticket_handlers)) != NULL) {
+               struct ceph_x_ticket_handler *th =
+                       rb_entry(p, struct ceph_x_ticket_handler, node);
+               remove_ticket_handler(ac, th);
+       }
+
+       kmem_cache_destroy(ceph_x_ticketbuf_cachep);
+
+       kfree(ac->private);
+       ac->private = NULL;
+}
+
+static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
+                                  int peer_type)
+{
+       struct ceph_x_ticket_handler *th;
+
+       th = get_ticket_handler(ac, peer_type);
+       if (th && !IS_ERR(th))
+               remove_ticket_handler(ac, th);
+}
+
+
+static const struct ceph_auth_client_ops ceph_x_ops = {
+       .is_authenticated = ceph_x_is_authenticated,
+       .build_request = ceph_x_build_request,
+       .handle_reply = ceph_x_handle_reply,
+       .create_authorizer = ceph_x_create_authorizer,
+       .verify_authorizer_reply = ceph_x_verify_authorizer_reply,
+       .destroy_authorizer = ceph_x_destroy_authorizer,
+       .invalidate_authorizer = ceph_x_invalidate_authorizer,
+       .reset =  ceph_x_reset,
+       .destroy = ceph_x_destroy,
+};
+
+
+int ceph_x_init(struct ceph_auth_client *ac)
+{
+       struct ceph_x_info *xi;
+       int ret;
+
+       dout("ceph_x_init %p\n", ac);
+       xi = kzalloc(sizeof(*xi), GFP_NOFS);
+       if (!xi)
+               return -ENOMEM;
+
+       ret = -ENOMEM;
+       ceph_x_ticketbuf_cachep = kmem_cache_create("ceph_x_ticketbuf",
+                                     TEMP_TICKET_BUF_LEN, 8,
+                                     (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
+                                     NULL);
+       if (!ceph_x_ticketbuf_cachep)
+               goto done_nomem;
+       ret = -EINVAL;
+       if (!ac->secret) {
+               pr_err("no secret set (for auth_x protocol)\n");
+               goto done_nomem;
+       }
+
+       ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret);
+       if (ret)
+               goto done_nomem;
+
+       xi->starting = true;
+       xi->ticket_handlers = RB_ROOT;
+
+       ac->protocol = CEPH_AUTH_CEPHX;
+       ac->private = xi;
+       ac->ops = &ceph_x_ops;
+       return 0;
+
+done_nomem:
+       kfree(xi);
+       if (ceph_x_ticketbuf_cachep)
+               kmem_cache_destroy(ceph_x_ticketbuf_cachep);
+       return ret;
+}
+
+
diff --git a/fs/ceph/auth_x.h b/fs/ceph/auth_x.h
new file mode 100644 (file)
index 0000000..ff6f818
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _FS_CEPH_AUTH_X_H
+#define _FS_CEPH_AUTH_X_H
+
+#include <linux/rbtree.h>
+
+#include "crypto.h"
+#include "auth.h"
+#include "auth_x_protocol.h"
+
+/*
+ * Handle ticket for a single service.
+ */
+struct ceph_x_ticket_handler {
+       struct rb_node node;
+       unsigned service;
+
+       struct ceph_crypto_key session_key;
+       struct ceph_timespec validity;
+
+       u64 secret_id;
+       struct ceph_buffer *ticket_blob;
+
+       unsigned long renew_after, expires;
+};
+
+
+struct ceph_x_authorizer {
+       struct ceph_buffer *buf;
+       unsigned service;
+       u64 nonce;
+       char reply_buf[128];  /* big enough for encrypted blob */
+};
+
+struct ceph_x_info {
+       struct ceph_crypto_key secret;
+
+       bool starting;
+       u64 server_challenge;
+
+       unsigned have_keys;
+       struct rb_root ticket_handlers;
+
+       struct ceph_x_authorizer auth_authorizer;
+};
+
+extern int ceph_x_init(struct ceph_auth_client *ac);
+
+#endif
+
diff --git a/fs/ceph/auth_x_protocol.h b/fs/ceph/auth_x_protocol.h
new file mode 100644 (file)
index 0000000..671d305
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef __FS_CEPH_AUTH_X_PROTOCOL
+#define __FS_CEPH_AUTH_X_PROTOCOL
+
+#define CEPHX_GET_AUTH_SESSION_KEY      0x0100
+#define CEPHX_GET_PRINCIPAL_SESSION_KEY 0x0200
+#define CEPHX_GET_ROTATING_KEY          0x0400
+
+/* common bits */
+struct ceph_x_ticket_blob {
+       __u8 struct_v;
+       __le64 secret_id;
+       __le32 blob_len;
+       char blob[];
+} __attribute__ ((packed));
+
+
+/* common request/reply headers */
+struct ceph_x_request_header {
+       __le16 op;
+} __attribute__ ((packed));
+
+struct ceph_x_reply_header {
+       __le16 op;
+       __le32 result;
+} __attribute__ ((packed));
+
+
+/* authenticate handshake */
+
+/* initial hello (no reply header) */
+struct ceph_x_server_challenge {
+       __u8 struct_v;
+       __le64 server_challenge;
+} __attribute__ ((packed));
+
+struct ceph_x_authenticate {
+       __u8 struct_v;
+       __le64 client_challenge;
+       __le64 key;
+       /* ticket blob */
+} __attribute__ ((packed));
+
+struct ceph_x_service_ticket_request {
+       __u8 struct_v;
+       __le32 keys;
+} __attribute__ ((packed));
+
+struct ceph_x_challenge_blob {
+       __le64 server_challenge;
+       __le64 client_challenge;
+} __attribute__ ((packed));
+
+
+
+/* authorize handshake */
+
+/*
+ * The authorizer consists of two pieces:
+ *  a - service id, ticket blob
+ *  b - encrypted with session key
+ */
+struct ceph_x_authorize_a {
+       __u8 struct_v;
+       __le64 global_id;
+       __le32 service_id;
+       struct ceph_x_ticket_blob ticket_blob;
+} __attribute__ ((packed));
+
+struct ceph_x_authorize_b {
+       __u8 struct_v;
+       __le64 nonce;
+} __attribute__ ((packed));
+
+struct ceph_x_authorize_reply {
+       __u8 struct_v;
+       __le64 nonce_plus_one;
+} __attribute__ ((packed));
+
+
+/*
+ * encyption bundle
+ */
+#define CEPHX_ENC_MAGIC 0xff009cad8826aa55ull
+
+struct ceph_x_encrypt_header {
+       __u8 struct_v;
+       __le64 magic;
+} __attribute__ ((packed));
+
+#endif
diff --git a/fs/ceph/buffer.c b/fs/ceph/buffer.c
new file mode 100644 (file)
index 0000000..b98086c
--- /dev/null
@@ -0,0 +1,78 @@
+
+#include "ceph_debug.h"
+#include "buffer.h"
+#include "decode.h"
+
+struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
+{
+       struct ceph_buffer *b;
+
+       b = kmalloc(sizeof(*b), gfp);
+       if (!b)
+               return NULL;
+
+       b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
+       if (b->vec.iov_base) {
+               b->is_vmalloc = false;
+       } else {
+               b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+               if (!b->vec.iov_base) {
+                       kfree(b);
+                       return NULL;
+               }
+               b->is_vmalloc = true;
+       }
+
+       kref_init(&b->kref);
+       b->alloc_len = len;
+       b->vec.iov_len = len;
+       dout("buffer_new %p\n", b);
+       return b;
+}
+
+void ceph_buffer_release(struct kref *kref)
+{
+       struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
+
+       dout("buffer_release %p\n", b);
+       if (b->vec.iov_base) {
+               if (b->is_vmalloc)
+                       vfree(b->vec.iov_base);
+               else
+                       kfree(b->vec.iov_base);
+       }
+       kfree(b);
+}
+
+int ceph_buffer_alloc(struct ceph_buffer *b, int len, gfp_t gfp)
+{
+       b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
+       if (b->vec.iov_base) {
+               b->is_vmalloc = false;
+       } else {
+               b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+               b->is_vmalloc = true;
+       }
+       if (!b->vec.iov_base)
+               return -ENOMEM;
+       b->alloc_len = len;
+       b->vec.iov_len = len;
+       return 0;
+}
+
+int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end)
+{
+       size_t len;
+
+       ceph_decode_need(p, end, sizeof(u32), bad);
+       len = ceph_decode_32(p);
+       dout("decode_buffer len %d\n", (int)len);
+       ceph_decode_need(p, end, len, bad);
+       *b = ceph_buffer_new(len, GFP_NOFS);
+       if (!*b)
+               return -ENOMEM;
+       ceph_decode_copy(p, (*b)->vec.iov_base, len);
+       return 0;
+bad:
+       return -EINVAL;
+}
diff --git a/fs/ceph/buffer.h b/fs/ceph/buffer.h
new file mode 100644 (file)
index 0000000..58d1901
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __FS_CEPH_BUFFER_H
+#define __FS_CEPH_BUFFER_H
+
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+
+/*
+ * a simple reference counted buffer.
+ *
+ * use kmalloc for small sizes (<= one page), vmalloc for larger
+ * sizes.
+ */
+struct ceph_buffer {
+       struct kref kref;
+       struct kvec vec;
+       size_t alloc_len;
+       bool is_vmalloc;
+};
+
+extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp);
+extern void ceph_buffer_release(struct kref *kref);
+
+static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b)
+{
+       kref_get(&b->kref);
+       return b;
+}
+
+static inline void ceph_buffer_put(struct ceph_buffer *b)
+{
+       kref_put(&b->kref, ceph_buffer_release);
+}
+
+extern int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end);
+
+#endif
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
new file mode 100644 (file)
index 0000000..db122bb
--- /dev/null
@@ -0,0 +1,2927 @@
+#include "ceph_debug.h"
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/writeback.h>
+
+#include "super.h"
+#include "decode.h"
+#include "messenger.h"
+
+/*
+ * Capability management
+ *
+ * The Ceph metadata servers control client access to inode metadata
+ * and file data by issuing capabilities, granting clients permission
+ * to read and/or write both inode field and file data to OSDs
+ * (storage nodes).  Each capability consists of a set of bits
+ * indicating which operations are allowed.
+ *
+ * If the client holds a *_SHARED cap, the client has a coherent value
+ * that can be safely read from the cached inode.
+ *
+ * In the case of a *_EXCL (exclusive) or FILE_WR capabilities, the
+ * client is allowed to change inode attributes (e.g., file size,
+ * mtime), note its dirty state in the ceph_cap, and asynchronously
+ * flush that metadata change to the MDS.
+ *
+ * In the event of a conflicting operation (perhaps by another
+ * client), the MDS will revoke the conflicting client capabilities.
+ *
+ * In order for a client to cache an inode, it must hold a capability
+ * with at least one MDS server.  When inodes are released, release
+ * notifications are batched and periodically sent en masse to the MDS
+ * cluster to release server state.
+ */
+
+
+/*
+ * Generate readable cap strings for debugging output.
+ */
+#define MAX_CAP_STR 20
+static char cap_str[MAX_CAP_STR][40];
+static DEFINE_SPINLOCK(cap_str_lock);
+static int last_cap_str;
+
+static char *gcap_string(char *s, int c)
+{
+       if (c & CEPH_CAP_GSHARED)
+               *s++ = 's';
+       if (c & CEPH_CAP_GEXCL)
+               *s++ = 'x';
+       if (c & CEPH_CAP_GCACHE)
+               *s++ = 'c';
+       if (c & CEPH_CAP_GRD)
+               *s++ = 'r';
+       if (c & CEPH_CAP_GWR)
+               *s++ = 'w';
+       if (c & CEPH_CAP_GBUFFER)
+               *s++ = 'b';
+       if (c & CEPH_CAP_GLAZYIO)
+               *s++ = 'l';
+       return s;
+}
+
+const char *ceph_cap_string(int caps)
+{
+       int i;
+       char *s;
+       int c;
+
+       spin_lock(&cap_str_lock);
+       i = last_cap_str++;
+       if (last_cap_str == MAX_CAP_STR)
+               last_cap_str = 0;
+       spin_unlock(&cap_str_lock);
+
+       s = cap_str[i];
+
+       if (caps & CEPH_CAP_PIN)
+               *s++ = 'p';
+
+       c = (caps >> CEPH_CAP_SAUTH) & 3;
+       if (c) {
+               *s++ = 'A';
+               s = gcap_string(s, c);
+       }
+
+       c = (caps >> CEPH_CAP_SLINK) & 3;
+       if (c) {
+               *s++ = 'L';
+               s = gcap_string(s, c);
+       }
+
+       c = (caps >> CEPH_CAP_SXATTR) & 3;
+       if (c) {
+               *s++ = 'X';
+               s = gcap_string(s, c);
+       }
+
+       c = caps >> CEPH_CAP_SFILE;
+       if (c) {
+               *s++ = 'F';
+               s = gcap_string(s, c);
+       }
+
+       if (s == cap_str[i])
+               *s++ = '-';
+       *s = 0;
+       return cap_str[i];
+}
+
+/*
+ * Cap reservations
+ *
+ * Maintain a global pool of preallocated struct ceph_caps, referenced
+ * by struct ceph_caps_reservations.  This ensures that we preallocate
+ * memory needed to successfully process an MDS response.  (If an MDS
+ * sends us cap information and we fail to process it, we will have
+ * problems due to the client and MDS being out of sync.)
+ *
+ * Reservations are 'owned' by a ceph_cap_reservation context.
+ */
+static spinlock_t caps_list_lock;
+static struct list_head caps_list;  /* unused (reserved or unreserved) */
+static int caps_total_count;        /* total caps allocated */
+static int caps_use_count;          /* in use */
+static int caps_reserve_count;      /* unused, reserved */
+static int caps_avail_count;        /* unused, unreserved */
+static int caps_min_count;          /* keep at least this many (unreserved) */
+
+void __init ceph_caps_init(void)
+{
+       INIT_LIST_HEAD(&caps_list);
+       spin_lock_init(&caps_list_lock);
+}
+
+void ceph_caps_finalize(void)
+{
+       struct ceph_cap *cap;
+
+       spin_lock(&caps_list_lock);
+       while (!list_empty(&caps_list)) {
+               cap = list_first_entry(&caps_list, struct ceph_cap, caps_item);
+               list_del(&cap->caps_item);
+               kmem_cache_free(ceph_cap_cachep, cap);
+       }
+       caps_total_count = 0;
+       caps_avail_count = 0;
+       caps_use_count = 0;
+       caps_reserve_count = 0;
+       caps_min_count = 0;
+       spin_unlock(&caps_list_lock);
+}
+
+void ceph_adjust_min_caps(int delta)
+{
+       spin_lock(&caps_list_lock);
+       caps_min_count += delta;
+       BUG_ON(caps_min_count < 0);
+       spin_unlock(&caps_list_lock);
+}
+
+int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need)
+{
+       int i;
+       struct ceph_cap *cap;
+       int have;
+       int alloc = 0;
+       LIST_HEAD(newcaps);
+       int ret = 0;
+
+       dout("reserve caps ctx=%p need=%d\n", ctx, need);
+
+       /* first reserve any caps that are already allocated */
+       spin_lock(&caps_list_lock);
+       if (caps_avail_count >= need)
+               have = need;
+       else
+               have = caps_avail_count;
+       caps_avail_count -= have;
+       caps_reserve_count += have;
+       BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+              caps_avail_count);
+       spin_unlock(&caps_list_lock);
+
+       for (i = have; i < need; i++) {
+               cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
+               if (!cap) {
+                       ret = -ENOMEM;
+                       goto out_alloc_count;
+               }
+               list_add(&cap->caps_item, &newcaps);
+               alloc++;
+       }
+       BUG_ON(have + alloc != need);
+
+       spin_lock(&caps_list_lock);
+       caps_total_count += alloc;
+       caps_reserve_count += alloc;
+       list_splice(&newcaps, &caps_list);
+
+       BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+              caps_avail_count);
+       spin_unlock(&caps_list_lock);
+
+       ctx->count = need;
+       dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n",
+            ctx, caps_total_count, caps_use_count, caps_reserve_count,
+            caps_avail_count);
+       return 0;
+
+out_alloc_count:
+       /* we didn't manage to reserve as much as we needed */
+       pr_warning("reserve caps ctx=%p ENOMEM need=%d got=%d\n",
+                  ctx, need, have);
+       return ret;
+}
+
+int ceph_unreserve_caps(struct ceph_cap_reservation *ctx)
+{
+       dout("unreserve caps ctx=%p count=%d\n", ctx, ctx->count);
+       if (ctx->count) {
+               spin_lock(&caps_list_lock);
+               BUG_ON(caps_reserve_count < ctx->count);
+               caps_reserve_count -= ctx->count;
+               caps_avail_count += ctx->count;
+               ctx->count = 0;
+               dout("unreserve caps %d = %d used + %d resv + %d avail\n",
+                    caps_total_count, caps_use_count, caps_reserve_count,
+                    caps_avail_count);
+               BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+                      caps_avail_count);
+               spin_unlock(&caps_list_lock);
+       }
+       return 0;
+}
+
+static struct ceph_cap *get_cap(struct ceph_cap_reservation *ctx)
+{
+       struct ceph_cap *cap = NULL;
+
+       /* temporary, until we do something about cap import/export */
+       if (!ctx)
+               return kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
+
+       spin_lock(&caps_list_lock);
+       dout("get_cap ctx=%p (%d) %d = %d used + %d resv + %d avail\n",
+            ctx, ctx->count, caps_total_count, caps_use_count,
+            caps_reserve_count, caps_avail_count);
+       BUG_ON(!ctx->count);
+       BUG_ON(ctx->count > caps_reserve_count);
+       BUG_ON(list_empty(&caps_list));
+
+       ctx->count--;
+       caps_reserve_count--;
+       caps_use_count++;
+
+       cap = list_first_entry(&caps_list, struct ceph_cap, caps_item);
+       list_del(&cap->caps_item);
+
+       BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+              caps_avail_count);
+       spin_unlock(&caps_list_lock);
+       return cap;
+}
+
+void ceph_put_cap(struct ceph_cap *cap)
+{
+       spin_lock(&caps_list_lock);
+       dout("put_cap %p %d = %d used + %d resv + %d avail\n",
+            cap, caps_total_count, caps_use_count,
+            caps_reserve_count, caps_avail_count);
+       caps_use_count--;
+       /*
+        * Keep some preallocated caps around (ceph_min_count), to
+        * avoid lots of free/alloc churn.
+        */
+       if (caps_avail_count >= caps_reserve_count + caps_min_count) {
+               caps_total_count--;
+               kmem_cache_free(ceph_cap_cachep, cap);
+       } else {
+               caps_avail_count++;
+               list_add(&cap->caps_item, &caps_list);
+       }
+
+       BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+              caps_avail_count);
+       spin_unlock(&caps_list_lock);
+}
+
+void ceph_reservation_status(struct ceph_client *client,
+                            int *total, int *avail, int *used, int *reserved,
+                            int *min)
+{
+       if (total)
+               *total = caps_total_count;
+       if (avail)
+               *avail = caps_avail_count;
+       if (used)
+               *used = caps_use_count;
+       if (reserved)
+               *reserved = caps_reserve_count;
+       if (min)
+               *min = caps_min_count;
+}
+
+/*
+ * Find ceph_cap for given mds, if any.
+ *
+ * Called with i_lock held.
+ */
+static struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds)
+{
+       struct ceph_cap *cap;
+       struct rb_node *n = ci->i_caps.rb_node;
+
+       while (n) {
+               cap = rb_entry(n, struct ceph_cap, ci_node);
+               if (mds < cap->mds)
+                       n = n->rb_left;
+               else if (mds > cap->mds)
+                       n = n->rb_right;
+               else
+                       return cap;
+       }
+       return NULL;
+}
+
+/*
+ * Return id of any MDS with a cap, preferably FILE_WR|WRBUFFER|EXCL, else
+ * -1.
+ */
+static int __ceph_get_cap_mds(struct ceph_inode_info *ci, u32 *mseq)
+{
+       struct ceph_cap *cap;
+       int mds = -1;
+       struct rb_node *p;
+
+       /* prefer mds with WR|WRBUFFER|EXCL caps */
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               mds = cap->mds;
+               if (mseq)
+                       *mseq = cap->mseq;
+               if (cap->issued & (CEPH_CAP_FILE_WR |
+                                  CEPH_CAP_FILE_BUFFER |
+                                  CEPH_CAP_FILE_EXCL))
+                       break;
+       }
+       return mds;
+}
+
+int ceph_get_cap_mds(struct inode *inode)
+{
+       int mds;
+       spin_lock(&inode->i_lock);
+       mds = __ceph_get_cap_mds(ceph_inode(inode), NULL);
+       spin_unlock(&inode->i_lock);
+       return mds;
+}
+
+/*
+ * Called under i_lock.
+ */
+static void __insert_cap_node(struct ceph_inode_info *ci,
+                             struct ceph_cap *new)
+{
+       struct rb_node **p = &ci->i_caps.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_cap *cap = NULL;
+
+       while (*p) {
+               parent = *p;
+               cap = rb_entry(parent, struct ceph_cap, ci_node);
+               if (new->mds < cap->mds)
+                       p = &(*p)->rb_left;
+               else if (new->mds > cap->mds)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->ci_node, parent, p);
+       rb_insert_color(&new->ci_node, &ci->i_caps);
+}
+
+/*
+ * (re)set cap hold timeouts, which control the delayed release
+ * of unused caps back to the MDS.  Should be called on cap use.
+ */
+static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
+                              struct ceph_inode_info *ci)
+{
+       struct ceph_mount_args *ma = mdsc->client->mount_args;
+
+       ci->i_hold_caps_min = round_jiffies(jiffies +
+                                           ma->caps_wanted_delay_min * HZ);
+       ci->i_hold_caps_max = round_jiffies(jiffies +
+                                           ma->caps_wanted_delay_max * HZ);
+       dout("__cap_set_timeouts %p min %lu max %lu\n", &ci->vfs_inode,
+            ci->i_hold_caps_min - jiffies, ci->i_hold_caps_max - jiffies);
+}
+
+/*
+ * (Re)queue cap at the end of the delayed cap release list.
+ *
+ * If I_FLUSH is set, leave the inode at the front of the list.
+ *
+ * Caller holds i_lock
+ *    -> we take mdsc->cap_delay_lock
+ */
+static void __cap_delay_requeue(struct ceph_mds_client *mdsc,
+                               struct ceph_inode_info *ci)
+{
+       __cap_set_timeouts(mdsc, ci);
+       dout("__cap_delay_requeue %p flags %d at %lu\n", &ci->vfs_inode,
+            ci->i_ceph_flags, ci->i_hold_caps_max);
+       if (!mdsc->stopping) {
+               spin_lock(&mdsc->cap_delay_lock);
+               if (!list_empty(&ci->i_cap_delay_list)) {
+                       if (ci->i_ceph_flags & CEPH_I_FLUSH)
+                               goto no_change;
+                       list_del_init(&ci->i_cap_delay_list);
+               }
+               list_add_tail(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
+no_change:
+               spin_unlock(&mdsc->cap_delay_lock);
+       }
+}
+
+/*
+ * Queue an inode for immediate writeback.  Mark inode with I_FLUSH,
+ * indicating we should send a cap message to flush dirty metadata
+ * asap, and move to the front of the delayed cap list.
+ */
+static void __cap_delay_requeue_front(struct ceph_mds_client *mdsc,
+                                     struct ceph_inode_info *ci)
+{
+       dout("__cap_delay_requeue_front %p\n", &ci->vfs_inode);
+       spin_lock(&mdsc->cap_delay_lock);
+       ci->i_ceph_flags |= CEPH_I_FLUSH;
+       if (!list_empty(&ci->i_cap_delay_list))
+               list_del_init(&ci->i_cap_delay_list);
+       list_add(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
+       spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Cancel delayed work on cap.
+ *
+ * Caller must hold i_lock.
+ */
+static void __cap_delay_cancel(struct ceph_mds_client *mdsc,
+                              struct ceph_inode_info *ci)
+{
+       dout("__cap_delay_cancel %p\n", &ci->vfs_inode);
+       if (list_empty(&ci->i_cap_delay_list))
+               return;
+       spin_lock(&mdsc->cap_delay_lock);
+       list_del_init(&ci->i_cap_delay_list);
+       spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Common issue checks for add_cap, handle_cap_grant.
+ */
+static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
+                             unsigned issued)
+{
+       unsigned had = __ceph_caps_issued(ci, NULL);
+
+       /*
+        * Each time we receive FILE_CACHE anew, we increment
+        * i_rdcache_gen.
+        */
+       if ((issued & CEPH_CAP_FILE_CACHE) &&
+           (had & CEPH_CAP_FILE_CACHE) == 0)
+               ci->i_rdcache_gen++;
+
+       /*
+        * if we are newly issued FILE_SHARED, clear I_COMPLETE; we
+        * don't know what happened to this directory while we didn't
+        * have the cap.
+        */
+       if ((issued & CEPH_CAP_FILE_SHARED) &&
+           (had & CEPH_CAP_FILE_SHARED) == 0) {
+               ci->i_shared_gen++;
+               if (S_ISDIR(ci->vfs_inode.i_mode)) {
+                       dout(" marking %p NOT complete\n", &ci->vfs_inode);
+                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+               }
+       }
+}
+
+/*
+ * Add a capability under the given MDS session.
+ *
+ * Caller should hold session snap_rwsem (read) and s_mutex.
+ *
+ * @fmode is the open file mode, if we are opening a file, otherwise
+ * it is < 0.  (This is so we can atomically add the cap and add an
+ * open file reference to it.)
+ */
+int ceph_add_cap(struct inode *inode,
+                struct ceph_mds_session *session, u64 cap_id,
+                int fmode, unsigned issued, unsigned wanted,
+                unsigned seq, unsigned mseq, u64 realmino, int flags,
+                struct ceph_cap_reservation *caps_reservation)
+{
+       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap *new_cap = NULL;
+       struct ceph_cap *cap;
+       int mds = session->s_mds;
+       int actual_wanted;
+
+       dout("add_cap %p mds%d cap %llx %s seq %d\n", inode,
+            session->s_mds, cap_id, ceph_cap_string(issued), seq);
+
+       /*
+        * If we are opening the file, include file mode wanted bits
+        * in wanted.
+        */
+       if (fmode >= 0)
+               wanted |= ceph_caps_for_mode(fmode);
+
+retry:
+       spin_lock(&inode->i_lock);
+       cap = __get_cap_for_mds(ci, mds);
+       if (!cap) {
+               if (new_cap) {
+                       cap = new_cap;
+                       new_cap = NULL;
+               } else {
+                       spin_unlock(&inode->i_lock);
+                       new_cap = get_cap(caps_reservation);
+                       if (new_cap == NULL)
+                               return -ENOMEM;
+                       goto retry;
+               }
+
+               cap->issued = 0;
+               cap->implemented = 0;
+               cap->mds = mds;
+               cap->mds_wanted = 0;
+
+               cap->ci = ci;
+               __insert_cap_node(ci, cap);
+
+               /* clear out old exporting info?  (i.e. on cap import) */
+               if (ci->i_cap_exporting_mds == mds) {
+                       ci->i_cap_exporting_issued = 0;
+                       ci->i_cap_exporting_mseq = 0;
+                       ci->i_cap_exporting_mds = -1;
+               }
+
+               /* add to session cap list */
+               cap->session = session;
+               spin_lock(&session->s_cap_lock);
+               list_add_tail(&cap->session_caps, &session->s_caps);
+               session->s_nr_caps++;
+               spin_unlock(&session->s_cap_lock);
+       }
+
+       if (!ci->i_snap_realm) {
+               /*
+                * add this inode to the appropriate snap realm
+                */
+               struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc,
+                                                              realmino);
+               if (realm) {
+                       ceph_get_snap_realm(mdsc, realm);
+                       spin_lock(&realm->inodes_with_caps_lock);
+                       ci->i_snap_realm = realm;
+                       list_add(&ci->i_snap_realm_item,
+                                &realm->inodes_with_caps);
+                       spin_unlock(&realm->inodes_with_caps_lock);
+               } else {
+                       pr_err("ceph_add_cap: couldn't find snap realm %llx\n",
+                              realmino);
+               }
+       }
+
+       __check_cap_issue(ci, cap, issued);
+
+       /*
+        * If we are issued caps we don't want, or the mds' wanted
+        * value appears to be off, queue a check so we'll release
+        * later and/or update the mds wanted value.
+        */
+       actual_wanted = __ceph_caps_wanted(ci);
+       if ((wanted & ~actual_wanted) ||
+           (issued & ~actual_wanted & CEPH_CAP_ANY_WR)) {
+               dout(" issued %s, mds wanted %s, actual %s, queueing\n",
+                    ceph_cap_string(issued), ceph_cap_string(wanted),
+                    ceph_cap_string(actual_wanted));
+               __cap_delay_requeue(mdsc, ci);
+       }
+
+       if (flags & CEPH_CAP_FLAG_AUTH)
+               ci->i_auth_cap = cap;
+       else if (ci->i_auth_cap == cap)
+               ci->i_auth_cap = NULL;
+
+       dout("add_cap inode %p (%llx.%llx) cap %p %s now %s seq %d mds%d\n",
+            inode, ceph_vinop(inode), cap, ceph_cap_string(issued),
+            ceph_cap_string(issued|cap->issued), seq, mds);
+       cap->cap_id = cap_id;
+       cap->issued = issued;
+       cap->implemented |= issued;
+       cap->mds_wanted |= wanted;
+       cap->seq = seq;
+       cap->issue_seq = seq;
+       cap->mseq = mseq;
+       cap->cap_gen = session->s_cap_gen;
+
+       if (fmode >= 0)
+               __ceph_get_fmode(ci, fmode);
+       spin_unlock(&inode->i_lock);
+       wake_up(&ci->i_cap_wq);
+       return 0;
+}
+
+/*
+ * Return true if cap has not timed out and belongs to the current
+ * generation of the MDS session (i.e. has not gone 'stale' due to
+ * us losing touch with the mds).
+ */
+static int __cap_is_valid(struct ceph_cap *cap)
+{
+       unsigned long ttl;
+       u32 gen;
+
+       spin_lock(&cap->session->s_cap_lock);
+       gen = cap->session->s_cap_gen;
+       ttl = cap->session->s_cap_ttl;
+       spin_unlock(&cap->session->s_cap_lock);
+
+       if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) {
+               dout("__cap_is_valid %p cap %p issued %s "
+                    "but STALE (gen %u vs %u)\n", &cap->ci->vfs_inode,
+                    cap, ceph_cap_string(cap->issued), cap->cap_gen, gen);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Return set of valid cap bits issued to us.  Note that caps time
+ * out, and may be invalidated in bulk if the client session times out
+ * and session->s_cap_gen is bumped.
+ */
+int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented)
+{
+       int have = ci->i_snap_caps | ci->i_cap_exporting_issued;
+       struct ceph_cap *cap;
+       struct rb_node *p;
+
+       if (implemented)
+               *implemented = 0;
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               if (!__cap_is_valid(cap))
+                       continue;
+               dout("__ceph_caps_issued %p cap %p issued %s\n",
+                    &ci->vfs_inode, cap, ceph_cap_string(cap->issued));
+               have |= cap->issued;
+               if (implemented)
+                       *implemented |= cap->implemented;
+       }
+       return have;
+}
+
+/*
+ * Get cap bits issued by caps other than @ocap
+ */
+int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap)
+{
+       int have = ci->i_snap_caps;
+       struct ceph_cap *cap;
+       struct rb_node *p;
+
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               if (cap == ocap)
+                       continue;
+               if (!__cap_is_valid(cap))
+                       continue;
+               have |= cap->issued;
+       }
+       return have;
+}
+
+/*
+ * Move a cap to the end of the LRU (oldest caps at list head, newest
+ * at list tail).
+ */
+static void __touch_cap(struct ceph_cap *cap)
+{
+       struct ceph_mds_session *s = cap->session;
+
+       spin_lock(&s->s_cap_lock);
+       if (s->s_cap_iterator == NULL) {
+               dout("__touch_cap %p cap %p mds%d\n", &cap->ci->vfs_inode, cap,
+                    s->s_mds);
+               list_move_tail(&cap->session_caps, &s->s_caps);
+       } else {
+               dout("__touch_cap %p cap %p mds%d NOP, iterating over caps\n",
+                    &cap->ci->vfs_inode, cap, s->s_mds);
+       }
+       spin_unlock(&s->s_cap_lock);
+}
+
+/*
+ * Check if we hold the given mask.  If so, move the cap(s) to the
+ * front of their respective LRUs.  (This is the preferred way for
+ * callers to check for caps they want.)
+ */
+int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+{
+       struct ceph_cap *cap;
+       struct rb_node *p;
+       int have = ci->i_snap_caps;
+
+       if ((have & mask) == mask) {
+               dout("__ceph_caps_issued_mask %p snap issued %s"
+                    " (mask %s)\n", &ci->vfs_inode,
+                    ceph_cap_string(have),
+                    ceph_cap_string(mask));
+               return 1;
+       }
+
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               if (!__cap_is_valid(cap))
+                       continue;
+               if ((cap->issued & mask) == mask) {
+                       dout("__ceph_caps_issued_mask %p cap %p issued %s"
+                            " (mask %s)\n", &ci->vfs_inode, cap,
+                            ceph_cap_string(cap->issued),
+                            ceph_cap_string(mask));
+                       if (touch)
+                               __touch_cap(cap);
+                       return 1;
+               }
+
+               /* does a combination of caps satisfy mask? */
+               have |= cap->issued;
+               if ((have & mask) == mask) {
+                       dout("__ceph_caps_issued_mask %p combo issued %s"
+                            " (mask %s)\n", &ci->vfs_inode,
+                            ceph_cap_string(cap->issued),
+                            ceph_cap_string(mask));
+                       if (touch) {
+                               struct rb_node *q;
+
+                               /* touch this + preceeding caps */
+                               __touch_cap(cap);
+                               for (q = rb_first(&ci->i_caps); q != p;
+                                    q = rb_next(q)) {
+                                       cap = rb_entry(q, struct ceph_cap,
+                                                      ci_node);
+                                       if (!__cap_is_valid(cap))
+                                               continue;
+                                       __touch_cap(cap);
+                               }
+                       }
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Return true if mask caps are currently being revoked by an MDS.
+ */
+int ceph_caps_revoking(struct ceph_inode_info *ci, int mask)
+{
+       struct inode *inode = &ci->vfs_inode;
+       struct ceph_cap *cap;
+       struct rb_node *p;
+       int ret = 0;
+
+       spin_lock(&inode->i_lock);
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               if (__cap_is_valid(cap) &&
+                   (cap->implemented & ~cap->issued & mask)) {
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock(&inode->i_lock);
+       dout("ceph_caps_revoking %p %s = %d\n", inode,
+            ceph_cap_string(mask), ret);
+       return ret;
+}
+
+int __ceph_caps_used(struct ceph_inode_info *ci)
+{
+       int used = 0;
+       if (ci->i_pin_ref)
+               used |= CEPH_CAP_PIN;
+       if (ci->i_rd_ref)
+               used |= CEPH_CAP_FILE_RD;
+       if (ci->i_rdcache_ref || ci->i_rdcache_gen)
+               used |= CEPH_CAP_FILE_CACHE;
+       if (ci->i_wr_ref)
+               used |= CEPH_CAP_FILE_WR;
+       if (ci->i_wrbuffer_ref)
+               used |= CEPH_CAP_FILE_BUFFER;
+       return used;
+}
+
+/*
+ * wanted, by virtue of open file modes
+ */
+int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
+{
+       int want = 0;
+       int mode;
+       for (mode = 0; mode < 4; mode++)
+               if (ci->i_nr_by_mode[mode])
+                       want |= ceph_caps_for_mode(mode);
+       return want;
+}
+
+/*
+ * Return caps we have registered with the MDS(s) as 'wanted'.
+ */
+int __ceph_caps_mds_wanted(struct ceph_inode_info *ci)
+{
+       struct ceph_cap *cap;
+       struct rb_node *p;
+       int mds_wanted = 0;
+
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               if (!__cap_is_valid(cap))
+                       continue;
+               mds_wanted |= cap->mds_wanted;
+       }
+       return mds_wanted;
+}
+
+/*
+ * called under i_lock
+ */
+static int __ceph_is_any_caps(struct ceph_inode_info *ci)
+{
+       return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0;
+}
+
+/*
+ * caller should hold i_lock.
+ * caller will not hold session s_mutex if called from destroy_inode.
+ */
+void __ceph_remove_cap(struct ceph_cap *cap)
+{
+       struct ceph_mds_session *session = cap->session;
+       struct ceph_inode_info *ci = cap->ci;
+       struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+
+       dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
+
+       /* remove from inode list */
+       rb_erase(&cap->ci_node, &ci->i_caps);
+       cap->ci = NULL;
+       if (ci->i_auth_cap == cap)
+               ci->i_auth_cap = NULL;
+
+       /* remove from session list */
+       spin_lock(&session->s_cap_lock);
+       if (session->s_cap_iterator == cap) {
+               /* not yet, we are iterating over this very cap */
+               dout("__ceph_remove_cap  delaying %p removal from session %p\n",
+                    cap, cap->session);
+       } else {
+               list_del_init(&cap->session_caps);
+               session->s_nr_caps--;
+               cap->session = NULL;
+       }
+       spin_unlock(&session->s_cap_lock);
+
+       if (cap->session == NULL)
+               ceph_put_cap(cap);
+
+       if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) {
+               struct ceph_snap_realm *realm = ci->i_snap_realm;
+               spin_lock(&realm->inodes_with_caps_lock);
+               list_del_init(&ci->i_snap_realm_item);
+               ci->i_snap_realm_counter++;
+               ci->i_snap_realm = NULL;
+               spin_unlock(&realm->inodes_with_caps_lock);
+               ceph_put_snap_realm(mdsc, realm);
+       }
+       if (!__ceph_is_any_real_caps(ci))
+               __cap_delay_cancel(mdsc, ci);
+}
+
+/*
+ * Build and send a cap message to the given MDS.
+ *
+ * Caller should be holding s_mutex.
+ */
+static int send_cap_msg(struct ceph_mds_session *session,
+                       u64 ino, u64 cid, int op,
+                       int caps, int wanted, int dirty,
+                       u32 seq, u64 flush_tid, u32 issue_seq, u32 mseq,
+                       u64 size, u64 max_size,
+                       struct timespec *mtime, struct timespec *atime,
+                       u64 time_warp_seq,
+                       uid_t uid, gid_t gid, mode_t mode,
+                       u64 xattr_version,
+                       struct ceph_buffer *xattrs_buf,
+                       u64 follows)
+{
+       struct ceph_mds_caps *fc;
+       struct ceph_msg *msg;
+
+       dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s"
+            " seq %u/%u mseq %u follows %lld size %llu/%llu"
+            " xattr_ver %llu xattr_len %d\n", ceph_cap_op_name(op),
+            cid, ino, ceph_cap_string(caps), ceph_cap_string(wanted),
+            ceph_cap_string(dirty),
+            seq, issue_seq, mseq, follows, size, max_size,
+            xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0);
+
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), 0, 0, NULL);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+
+       msg->hdr.tid = cpu_to_le64(flush_tid);
+
+       fc = msg->front.iov_base;
+       memset(fc, 0, sizeof(*fc));
+
+       fc->cap_id = cpu_to_le64(cid);
+       fc->op = cpu_to_le32(op);
+       fc->seq = cpu_to_le32(seq);
+       fc->issue_seq = cpu_to_le32(issue_seq);
+       fc->migrate_seq = cpu_to_le32(mseq);
+       fc->caps = cpu_to_le32(caps);
+       fc->wanted = cpu_to_le32(wanted);
+       fc->dirty = cpu_to_le32(dirty);
+       fc->ino = cpu_to_le64(ino);
+       fc->snap_follows = cpu_to_le64(follows);
+
+       fc->size = cpu_to_le64(size);
+       fc->max_size = cpu_to_le64(max_size);
+       if (mtime)
+               ceph_encode_timespec(&fc->mtime, mtime);
+       if (atime)
+               ceph_encode_timespec(&fc->atime, atime);
+       fc->time_warp_seq = cpu_to_le32(time_warp_seq);
+
+       fc->uid = cpu_to_le32(uid);
+       fc->gid = cpu_to_le32(gid);
+       fc->mode = cpu_to_le32(mode);
+
+       fc->xattr_version = cpu_to_le64(xattr_version);
+       if (xattrs_buf) {
+               msg->middle = ceph_buffer_get(xattrs_buf);
+               fc->xattr_len = cpu_to_le32(xattrs_buf->vec.iov_len);
+               msg->hdr.middle_len = cpu_to_le32(xattrs_buf->vec.iov_len);
+       }
+
+       ceph_con_send(&session->s_con, msg);
+       return 0;
+}
+
+/*
+ * Queue cap releases when an inode is dropped from our cache.  Since
+ * inode is about to be destroyed, there is no need for i_lock.
+ */
+void ceph_queue_caps_release(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct rb_node *p;
+
+       p = rb_first(&ci->i_caps);
+       while (p) {
+               struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
+               struct ceph_mds_session *session = cap->session;
+               struct ceph_msg *msg;
+               struct ceph_mds_cap_release *head;
+               struct ceph_mds_cap_item *item;
+
+               spin_lock(&session->s_cap_lock);
+               BUG_ON(!session->s_num_cap_releases);
+               msg = list_first_entry(&session->s_cap_releases,
+                                      struct ceph_msg, list_head);
+
+               dout(" adding %p release to mds%d msg %p (%d left)\n",
+                    inode, session->s_mds, msg, session->s_num_cap_releases);
+
+               BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE);
+               head = msg->front.iov_base;
+               head->num = cpu_to_le32(le32_to_cpu(head->num) + 1);
+               item = msg->front.iov_base + msg->front.iov_len;
+               item->ino = cpu_to_le64(ceph_ino(inode));
+               item->cap_id = cpu_to_le64(cap->cap_id);
+               item->migrate_seq = cpu_to_le32(cap->mseq);
+               item->seq = cpu_to_le32(cap->issue_seq);
+
+               session->s_num_cap_releases--;
+
+               msg->front.iov_len += sizeof(*item);
+               if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) {
+                       dout(" release msg %p full\n", msg);
+                       list_move_tail(&msg->list_head,
+                                      &session->s_cap_releases_done);
+               } else {
+                       dout(" release msg %p at %d/%d (%d)\n", msg,
+                            (int)le32_to_cpu(head->num),
+                            (int)CEPH_CAPS_PER_RELEASE,
+                            (int)msg->front.iov_len);
+               }
+               spin_unlock(&session->s_cap_lock);
+               p = rb_next(p);
+               __ceph_remove_cap(cap);
+       }
+}
+
+/*
+ * Send a cap msg on the given inode.  Update our caps state, then
+ * drop i_lock and send the message.
+ *
+ * Make note of max_size reported/requested from mds, revoked caps
+ * that have now been implemented.
+ *
+ * Make half-hearted attempt ot to invalidate page cache if we are
+ * dropping RDCACHE.  Note that this will leave behind locked pages
+ * that we'll then need to deal with elsewhere.
+ *
+ * Return non-zero if delayed release, or we experienced an error
+ * such that the caller should requeue + retry later.
+ *
+ * called with i_lock, then drops it.
+ * caller should hold snap_rwsem (read), s_mutex.
+ */
+static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
+                     int op, int used, int want, int retain, int flushing,
+                     unsigned *pflush_tid)
+       __releases(cap->ci->vfs_inode->i_lock)
+{
+       struct ceph_inode_info *ci = cap->ci;
+       struct inode *inode = &ci->vfs_inode;
+       u64 cap_id = cap->cap_id;
+       int held, revoking, dropping, keep;
+       u64 seq, issue_seq, mseq, time_warp_seq, follows;
+       u64 size, max_size;
+       struct timespec mtime, atime;
+       int wake = 0;
+       mode_t mode;
+       uid_t uid;
+       gid_t gid;
+       struct ceph_mds_session *session;
+       u64 xattr_version = 0;
+       int delayed = 0;
+       u64 flush_tid = 0;
+       int i;
+       int ret;
+
+       held = cap->issued | cap->implemented;
+       revoking = cap->implemented & ~cap->issued;
+       retain &= ~revoking;
+       dropping = cap->issued & ~retain;
+
+       dout("__send_cap %p cap %p session %p %s -> %s (revoking %s)\n",
+            inode, cap, cap->session,
+            ceph_cap_string(held), ceph_cap_string(held & retain),
+            ceph_cap_string(revoking));
+       BUG_ON((retain & CEPH_CAP_PIN) == 0);
+
+       session = cap->session;
+
+       /* don't release wanted unless we've waited a bit. */
+       if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
+           time_before(jiffies, ci->i_hold_caps_min)) {
+               dout(" delaying issued %s -> %s, wanted %s -> %s on send\n",
+                    ceph_cap_string(cap->issued),
+                    ceph_cap_string(cap->issued & retain),
+                    ceph_cap_string(cap->mds_wanted),
+                    ceph_cap_string(want));
+               want |= cap->mds_wanted;
+               retain |= cap->issued;
+               delayed = 1;
+       }
+       ci->i_ceph_flags &= ~(CEPH_I_NODELAY | CEPH_I_FLUSH);
+
+       cap->issued &= retain;  /* drop bits we don't want */
+       if (cap->implemented & ~cap->issued) {
+               /*
+                * Wake up any waiters on wanted -> needed transition.
+                * This is due to the weird transition from buffered
+                * to sync IO... we need to flush dirty pages _before_
+                * allowing sync writes to avoid reordering.
+                */
+               wake = 1;
+       }
+       cap->implemented &= cap->issued | used;
+       cap->mds_wanted = want;
+
+       if (flushing) {
+               /*
+                * assign a tid for flush operations so we can avoid
+                * flush1 -> dirty1 -> flush2 -> flushack1 -> mark
+                * clean type races.  track latest tid for every bit
+                * so we can handle flush AxFw, flush Fw, and have the
+                * first ack clean Ax.
+                */
+               flush_tid = ++ci->i_cap_flush_last_tid;
+               if (pflush_tid)
+                       *pflush_tid = flush_tid;
+               dout(" cap_flush_tid %d\n", (int)flush_tid);
+               for (i = 0; i < CEPH_CAP_BITS; i++)
+                       if (flushing & (1 << i))
+                               ci->i_cap_flush_tid[i] = flush_tid;
+       }
+
+       keep = cap->implemented;
+       seq = cap->seq;
+       issue_seq = cap->issue_seq;
+       mseq = cap->mseq;
+       size = inode->i_size;
+       ci->i_reported_size = size;
+       max_size = ci->i_wanted_max_size;
+       ci->i_requested_max_size = max_size;
+       mtime = inode->i_mtime;
+       atime = inode->i_atime;
+       time_warp_seq = ci->i_time_warp_seq;
+       follows = ci->i_snap_realm->cached_context->seq;
+       uid = inode->i_uid;
+       gid = inode->i_gid;
+       mode = inode->i_mode;
+
+       if (dropping & CEPH_CAP_XATTR_EXCL) {
+               __ceph_build_xattrs_blob(ci);
+               xattr_version = ci->i_xattrs.version + 1;
+       }
+
+       spin_unlock(&inode->i_lock);
+
+       ret = send_cap_msg(session, ceph_vino(inode).ino, cap_id,
+               op, keep, want, flushing, seq, flush_tid, issue_seq, mseq,
+               size, max_size, &mtime, &atime, time_warp_seq,
+               uid, gid, mode,
+               xattr_version,
+               (flushing & CEPH_CAP_XATTR_EXCL) ? ci->i_xattrs.blob : NULL,
+               follows);
+       if (ret < 0) {
+               dout("error sending cap msg, must requeue %p\n", inode);
+               delayed = 1;
+       }
+
+       if (wake)
+               wake_up(&ci->i_cap_wq);
+
+       return delayed;
+}
+
+/*
+ * When a snapshot is taken, clients accumulate dirty metadata on
+ * inodes with capabilities in ceph_cap_snaps to describe the file
+ * state at the time the snapshot was taken.  This must be flushed
+ * asynchronously back to the MDS once sync writes complete and dirty
+ * data is written out.
+ *
+ * Called under i_lock.  Takes s_mutex as needed.
+ */
+void __ceph_flush_snaps(struct ceph_inode_info *ci,
+                       struct ceph_mds_session **psession)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int mds;
+       struct ceph_cap_snap *capsnap;
+       u32 mseq;
+       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_session *session = NULL; /* if session != NULL, we hold
+                                                   session->s_mutex */
+       u64 next_follows = 0;  /* keep track of how far we've gotten through the
+                            i_cap_snaps list, and skip these entries next time
+                            around to avoid an infinite loop */
+
+       if (psession)
+               session = *psession;
+
+       dout("__flush_snaps %p\n", inode);
+retry:
+       list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+               /* avoid an infiniute loop after retry */
+               if (capsnap->follows < next_follows)
+                       continue;
+               /*
+                * we need to wait for sync writes to complete and for dirty
+                * pages to be written out.
+                */
+               if (capsnap->dirty_pages || capsnap->writing)
+                       continue;
+
+               /* pick mds, take s_mutex */
+               mds = __ceph_get_cap_mds(ci, &mseq);
+               if (session && session->s_mds != mds) {
+                       dout("oops, wrong session %p mutex\n", session);
+                       mutex_unlock(&session->s_mutex);
+                       ceph_put_mds_session(session);
+                       session = NULL;
+               }
+               if (!session) {
+                       spin_unlock(&inode->i_lock);
+                       mutex_lock(&mdsc->mutex);
+                       session = __ceph_lookup_mds_session(mdsc, mds);
+                       mutex_unlock(&mdsc->mutex);
+                       if (session) {
+                               dout("inverting session/ino locks on %p\n",
+                                    session);
+                               mutex_lock(&session->s_mutex);
+                       }
+                       /*
+                        * if session == NULL, we raced against a cap
+                        * deletion.  retry, and we'll get a better
+                        * @mds value next time.
+                        */
+                       spin_lock(&inode->i_lock);
+                       goto retry;
+               }
+
+               capsnap->flush_tid = ++ci->i_cap_flush_last_tid;
+               atomic_inc(&capsnap->nref);
+               if (!list_empty(&capsnap->flushing_item))
+                       list_del_init(&capsnap->flushing_item);
+               list_add_tail(&capsnap->flushing_item,
+                             &session->s_cap_snaps_flushing);
+               spin_unlock(&inode->i_lock);
+
+               dout("flush_snaps %p cap_snap %p follows %lld size %llu\n",
+                    inode, capsnap, next_follows, capsnap->size);
+               send_cap_msg(session, ceph_vino(inode).ino, 0,
+                            CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
+                            capsnap->dirty, 0, capsnap->flush_tid, 0, mseq,
+                            capsnap->size, 0,
+                            &capsnap->mtime, &capsnap->atime,
+                            capsnap->time_warp_seq,
+                            capsnap->uid, capsnap->gid, capsnap->mode,
+                            0, NULL,
+                            capsnap->follows);
+
+               next_follows = capsnap->follows + 1;
+               ceph_put_cap_snap(capsnap);
+
+               spin_lock(&inode->i_lock);
+               goto retry;
+       }
+
+       /* we flushed them all; remove this inode from the queue */
+       spin_lock(&mdsc->snap_flush_lock);
+       list_del_init(&ci->i_snap_flush_item);
+       spin_unlock(&mdsc->snap_flush_lock);
+
+       if (psession)
+               *psession = session;
+       else if (session) {
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+       }
+}
+
+static void ceph_flush_snaps(struct ceph_inode_info *ci)
+{
+       struct inode *inode = &ci->vfs_inode;
+
+       spin_lock(&inode->i_lock);
+       __ceph_flush_snaps(ci, NULL);
+       spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Mark caps dirty.  If inode is newly dirty, add to the global dirty
+ * list.
+ */
+void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
+{
+       struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+       struct inode *inode = &ci->vfs_inode;
+       int was = ci->i_dirty_caps;
+       int dirty = 0;
+
+       dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode,
+            ceph_cap_string(mask), ceph_cap_string(was),
+            ceph_cap_string(was | mask));
+       ci->i_dirty_caps |= mask;
+       if (was == 0) {
+               dout(" inode %p now dirty\n", &ci->vfs_inode);
+               BUG_ON(!list_empty(&ci->i_dirty_item));
+               spin_lock(&mdsc->cap_dirty_lock);
+               list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
+               spin_unlock(&mdsc->cap_dirty_lock);
+               if (ci->i_flushing_caps == 0) {
+                       igrab(inode);
+                       dirty |= I_DIRTY_SYNC;
+               }
+       }
+       BUG_ON(list_empty(&ci->i_dirty_item));
+       if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) &&
+           (mask & CEPH_CAP_FILE_BUFFER))
+               dirty |= I_DIRTY_DATASYNC;
+       if (dirty)
+               __mark_inode_dirty(inode, dirty);
+       __cap_delay_requeue(mdsc, ci);
+}
+
+/*
+ * Add dirty inode to the flushing list.  Assigned a seq number so we
+ * can wait for caps to flush without starving.
+ *
+ * Called under i_lock.
+ */
+static int __mark_caps_flushing(struct inode *inode,
+                                struct ceph_mds_session *session)
+{
+       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int flushing;
+
+       BUG_ON(ci->i_dirty_caps == 0);
+       BUG_ON(list_empty(&ci->i_dirty_item));
+
+       flushing = ci->i_dirty_caps;
+       dout("__mark_caps_flushing flushing %s, flushing_caps %s -> %s\n",
+            ceph_cap_string(flushing),
+            ceph_cap_string(ci->i_flushing_caps),
+            ceph_cap_string(ci->i_flushing_caps | flushing));
+       ci->i_flushing_caps |= flushing;
+       ci->i_dirty_caps = 0;
+       dout(" inode %p now !dirty\n", inode);
+
+       spin_lock(&mdsc->cap_dirty_lock);
+       list_del_init(&ci->i_dirty_item);
+
+       ci->i_cap_flush_seq = ++mdsc->cap_flush_seq;
+       if (list_empty(&ci->i_flushing_item)) {
+               list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing);
+               mdsc->num_cap_flushing++;
+               dout(" inode %p now flushing seq %lld\n", inode,
+                    ci->i_cap_flush_seq);
+       } else {
+               list_move_tail(&ci->i_flushing_item, &session->s_cap_flushing);
+               dout(" inode %p now flushing (more) seq %lld\n", inode,
+                    ci->i_cap_flush_seq);
+       }
+       spin_unlock(&mdsc->cap_dirty_lock);
+
+       return flushing;
+}
+
+/*
+ * try to invalidate mapping pages without blocking.
+ */
+static int mapping_is_empty(struct address_space *mapping)
+{
+       struct page *page = find_get_page(mapping, 0);
+
+       if (!page)
+               return 1;
+
+       put_page(page);
+       return 0;
+}
+
+static int try_nonblocking_invalidate(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       u32 invalidating_gen = ci->i_rdcache_gen;
+
+       spin_unlock(&inode->i_lock);
+       invalidate_mapping_pages(&inode->i_data, 0, -1);
+       spin_lock(&inode->i_lock);
+
+       if (mapping_is_empty(&inode->i_data) &&
+           invalidating_gen == ci->i_rdcache_gen) {
+               /* success. */
+               dout("try_nonblocking_invalidate %p success\n", inode);
+               ci->i_rdcache_gen = 0;
+               ci->i_rdcache_revoking = 0;
+               return 0;
+       }
+       dout("try_nonblocking_invalidate %p failed\n", inode);
+       return -1;
+}
+
+/*
+ * Swiss army knife function to examine currently used and wanted
+ * versus held caps.  Release, flush, ack revoked caps to mds as
+ * appropriate.
+ *
+ *  CHECK_CAPS_NODELAY - caller is delayed work and we should not delay
+ *    cap release further.
+ *  CHECK_CAPS_AUTHONLY - we should only check the auth cap
+ *  CHECK_CAPS_FLUSH - we should flush any dirty caps immediately, without
+ *    further delay.
+ */
+void ceph_check_caps(struct ceph_inode_info *ci, int flags,
+                    struct ceph_mds_session *session)
+{
+       struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct inode *inode = &ci->vfs_inode;
+       struct ceph_cap *cap;
+       int file_wanted, used;
+       int took_snap_rwsem = 0;             /* true if mdsc->snap_rwsem held */
+       int drop_session_lock = session ? 0 : 1;
+       int issued, implemented, want, retain, revoking, flushing = 0;
+       int mds = -1;   /* keep track of how far we've gone through i_caps list
+                          to avoid an infinite loop on retry */
+       struct rb_node *p;
+       int tried_invalidate = 0;
+       int delayed = 0, sent = 0, force_requeue = 0, num;
+       int queue_invalidate = 0;
+       int is_delayed = flags & CHECK_CAPS_NODELAY;
+
+       /* if we are unmounting, flush any unused caps immediately. */
+       if (mdsc->stopping)
+               is_delayed = 1;
+
+       spin_lock(&inode->i_lock);
+
+       if (ci->i_ceph_flags & CEPH_I_FLUSH)
+               flags |= CHECK_CAPS_FLUSH;
+
+       /* flush snaps first time around only */
+       if (!list_empty(&ci->i_cap_snaps))
+               __ceph_flush_snaps(ci, &session);
+       goto retry_locked;
+retry:
+       spin_lock(&inode->i_lock);
+retry_locked:
+       file_wanted = __ceph_caps_file_wanted(ci);
+       used = __ceph_caps_used(ci);
+       want = file_wanted | used;
+       issued = __ceph_caps_issued(ci, &implemented);
+       revoking = implemented & ~issued;
+
+       retain = want | CEPH_CAP_PIN;
+       if (!mdsc->stopping && inode->i_nlink > 0) {
+               if (want) {
+                       retain |= CEPH_CAP_ANY;       /* be greedy */
+               } else {
+                       retain |= CEPH_CAP_ANY_SHARED;
+                       /*
+                        * keep RD only if we didn't have the file open RW,
+                        * because then the mds would revoke it anyway to
+                        * journal max_size=0.
+                        */
+                       if (ci->i_max_size == 0)
+                               retain |= CEPH_CAP_ANY_RD;
+               }
+       }
+
+       dout("check_caps %p file_want %s used %s dirty %s flushing %s"
+            " issued %s revoking %s retain %s %s%s%s\n", inode,
+            ceph_cap_string(file_wanted),
+            ceph_cap_string(used), ceph_cap_string(ci->i_dirty_caps),
+            ceph_cap_string(ci->i_flushing_caps),
+            ceph_cap_string(issued), ceph_cap_string(revoking),
+            ceph_cap_string(retain),
+            (flags & CHECK_CAPS_AUTHONLY) ? " AUTHONLY" : "",
+            (flags & CHECK_CAPS_NODELAY) ? " NODELAY" : "",
+            (flags & CHECK_CAPS_FLUSH) ? " FLUSH" : "");
+
+       /*
+        * If we no longer need to hold onto old our caps, and we may
+        * have cached pages, but don't want them, then try to invalidate.
+        * If we fail, it's because pages are locked.... try again later.
+        */
+       if ((!is_delayed || mdsc->stopping) &&
+           ci->i_wrbuffer_ref == 0 &&               /* no dirty pages... */
+           ci->i_rdcache_gen &&                     /* may have cached pages */
+           (file_wanted == 0 ||                     /* no open files */
+            (revoking & CEPH_CAP_FILE_CACHE)) &&     /*  or revoking cache */
+           !tried_invalidate) {
+               dout("check_caps trying to invalidate on %p\n", inode);
+               if (try_nonblocking_invalidate(inode) < 0) {
+                       if (revoking & CEPH_CAP_FILE_CACHE) {
+                               dout("check_caps queuing invalidate\n");
+                               queue_invalidate = 1;
+                               ci->i_rdcache_revoking = ci->i_rdcache_gen;
+                       } else {
+                               dout("check_caps failed to invalidate pages\n");
+                               /* we failed to invalidate pages.  check these
+                                  caps again later. */
+                               force_requeue = 1;
+                               __cap_set_timeouts(mdsc, ci);
+                       }
+               }
+               tried_invalidate = 1;
+               goto retry_locked;
+       }
+
+       num = 0;
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               cap = rb_entry(p, struct ceph_cap, ci_node);
+               num++;
+
+               /* avoid looping forever */
+               if (mds >= cap->mds ||
+                   ((flags & CHECK_CAPS_AUTHONLY) && cap != ci->i_auth_cap))
+                       continue;
+
+               /* NOTE: no side-effects allowed, until we take s_mutex */
+
+               revoking = cap->implemented & ~cap->issued;
+               if (revoking)
+                       dout(" mds%d revoking %s\n", cap->mds,
+                            ceph_cap_string(revoking));
+
+               if (cap == ci->i_auth_cap &&
+                   (cap->issued & CEPH_CAP_FILE_WR)) {
+                       /* request larger max_size from MDS? */
+                       if (ci->i_wanted_max_size > ci->i_max_size &&
+                           ci->i_wanted_max_size > ci->i_requested_max_size) {
+                               dout("requesting new max_size\n");
+                               goto ack;
+                       }
+
+                       /* approaching file_max? */
+                       if ((inode->i_size << 1) >= ci->i_max_size &&
+                           (ci->i_reported_size << 1) < ci->i_max_size) {
+                               dout("i_size approaching max_size\n");
+                               goto ack;
+                       }
+               }
+               /* flush anything dirty? */
+               if (cap == ci->i_auth_cap && (flags & CHECK_CAPS_FLUSH) &&
+                   ci->i_dirty_caps) {
+                       dout("flushing dirty caps\n");
+                       goto ack;
+               }
+
+               /* completed revocation? going down and there are no caps? */
+               if (revoking && (revoking & used) == 0) {
+                       dout("completed revocation of %s\n",
+                            ceph_cap_string(cap->implemented & ~cap->issued));
+                       goto ack;
+               }
+
+               /* want more caps from mds? */
+               if (want & ~(cap->mds_wanted | cap->issued))
+                       goto ack;
+
+               /* things we might delay */
+               if ((cap->issued & ~retain) == 0 &&
+                   cap->mds_wanted == want)
+                       continue;     /* nope, all good */
+
+               if (is_delayed)
+                       goto ack;
+
+               /* delay? */
+               if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
+                   time_before(jiffies, ci->i_hold_caps_max)) {
+                       dout(" delaying issued %s -> %s, wanted %s -> %s\n",
+                            ceph_cap_string(cap->issued),
+                            ceph_cap_string(cap->issued & retain),
+                            ceph_cap_string(cap->mds_wanted),
+                            ceph_cap_string(want));
+                       delayed++;
+                       continue;
+               }
+
+ack:
+               if (ci->i_ceph_flags & CEPH_I_NOFLUSH) {
+                       dout(" skipping %p I_NOFLUSH set\n", inode);
+                       continue;
+               }
+
+               if (session && session != cap->session) {
+                       dout("oops, wrong session %p mutex\n", session);
+                       mutex_unlock(&session->s_mutex);
+                       session = NULL;
+               }
+               if (!session) {
+                       session = cap->session;
+                       if (mutex_trylock(&session->s_mutex) == 0) {
+                               dout("inverting session/ino locks on %p\n",
+                                    session);
+                               spin_unlock(&inode->i_lock);
+                               if (took_snap_rwsem) {
+                                       up_read(&mdsc->snap_rwsem);
+                                       took_snap_rwsem = 0;
+                               }
+                               mutex_lock(&session->s_mutex);
+                               goto retry;
+                       }
+               }
+               /* take snap_rwsem after session mutex */
+               if (!took_snap_rwsem) {
+                       if (down_read_trylock(&mdsc->snap_rwsem) == 0) {
+                               dout("inverting snap/in locks on %p\n",
+                                    inode);
+                               spin_unlock(&inode->i_lock);
+                               down_read(&mdsc->snap_rwsem);
+                               took_snap_rwsem = 1;
+                               goto retry;
+                       }
+                       took_snap_rwsem = 1;
+               }
+
+               if (cap == ci->i_auth_cap && ci->i_dirty_caps)
+                       flushing = __mark_caps_flushing(inode, session);
+
+               mds = cap->mds;  /* remember mds, so we don't repeat */
+               sent++;
+
+               /* __send_cap drops i_lock */
+               delayed += __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, used, want,
+                                     retain, flushing, NULL);
+               goto retry; /* retake i_lock and restart our cap scan. */
+       }
+
+       /*
+        * Reschedule delayed caps release if we delayed anything,
+        * otherwise cancel.
+        */
+       if (delayed && is_delayed)
+               force_requeue = 1;   /* __send_cap delayed release; requeue */
+       if (!delayed && !is_delayed)
+               __cap_delay_cancel(mdsc, ci);
+       else if (!is_delayed || force_requeue)
+               __cap_delay_requeue(mdsc, ci);
+
+       spin_unlock(&inode->i_lock);
+
+       if (queue_invalidate)
+               ceph_queue_invalidate(inode);
+
+       if (session && drop_session_lock)
+               mutex_unlock(&session->s_mutex);
+       if (took_snap_rwsem)
+               up_read(&mdsc->snap_rwsem);
+}
+
+/*
+ * Try to flush dirty caps back to the auth mds.
+ */
+static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
+                         unsigned *flush_tid)
+{
+       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int unlock_session = session ? 0 : 1;
+       int flushing = 0;
+
+retry:
+       spin_lock(&inode->i_lock);
+       if (ci->i_ceph_flags & CEPH_I_NOFLUSH) {
+               dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode);
+               goto out;
+       }
+       if (ci->i_dirty_caps && ci->i_auth_cap) {
+               struct ceph_cap *cap = ci->i_auth_cap;
+               int used = __ceph_caps_used(ci);
+               int want = __ceph_caps_wanted(ci);
+               int delayed;
+
+               if (!session) {
+                       spin_unlock(&inode->i_lock);
+                       session = cap->session;
+                       mutex_lock(&session->s_mutex);
+                       goto retry;
+               }
+               BUG_ON(session != cap->session);
+               if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
+                       goto out;
+
+               flushing = __mark_caps_flushing(inode, session);
+
+               /* __send_cap drops i_lock */
+               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, used, want,
+                                    cap->issued | cap->implemented, flushing,
+                                    flush_tid);
+               if (!delayed)
+                       goto out_unlocked;
+
+               spin_lock(&inode->i_lock);
+               __cap_delay_requeue(mdsc, ci);
+       }
+out:
+       spin_unlock(&inode->i_lock);
+out_unlocked:
+       if (session && unlock_session)
+               mutex_unlock(&session->s_mutex);
+       return flushing;
+}
+
+/*
+ * Return true if we've flushed caps through the given flush_tid.
+ */
+static int caps_are_flushed(struct inode *inode, unsigned tid)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int dirty, i, ret = 1;
+
+       spin_lock(&inode->i_lock);
+       dirty = __ceph_caps_dirty(ci);
+       for (i = 0; i < CEPH_CAP_BITS; i++)
+               if ((ci->i_flushing_caps & (1 << i)) &&
+                   ci->i_cap_flush_tid[i] <= tid) {
+                       /* still flushing this bit */
+                       ret = 0;
+                       break;
+               }
+       spin_unlock(&inode->i_lock);
+       return ret;
+}
+
+/*
+ * Wait on any unsafe replies for the given inode.  First wait on the
+ * newest request, and make that the upper bound.  Then, if there are
+ * more requests, keep waiting on the oldest as long as it is still older
+ * than the original request.
+ */
+static void sync_write_wait(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct list_head *head = &ci->i_unsafe_writes;
+       struct ceph_osd_request *req;
+       u64 last_tid;
+
+       spin_lock(&ci->i_unsafe_lock);
+       if (list_empty(head))
+               goto out;
+
+       /* set upper bound as _last_ entry in chain */
+       req = list_entry(head->prev, struct ceph_osd_request,
+                        r_unsafe_item);
+       last_tid = req->r_tid;
+
+       do {
+               ceph_osdc_get_request(req);
+               spin_unlock(&ci->i_unsafe_lock);
+               dout("sync_write_wait on tid %llu (until %llu)\n",
+                    req->r_tid, last_tid);
+               wait_for_completion(&req->r_safe_completion);
+               spin_lock(&ci->i_unsafe_lock);
+               ceph_osdc_put_request(req);
+
+               /*
+                * from here on look at first entry in chain, since we
+                * only want to wait for anything older than last_tid
+                */
+               if (list_empty(head))
+                       break;
+               req = list_entry(head->next, struct ceph_osd_request,
+                                r_unsafe_item);
+       } while (req->r_tid < last_tid);
+out:
+       spin_unlock(&ci->i_unsafe_lock);
+}
+
+int ceph_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       unsigned flush_tid;
+       int ret;
+       int dirty;
+
+       dout("fsync %p%s\n", inode, datasync ? " datasync" : "");
+       sync_write_wait(inode);
+
+       ret = filemap_write_and_wait(inode->i_mapping);
+       if (ret < 0)
+               return ret;
+
+       dirty = try_flush_caps(inode, NULL, &flush_tid);
+       dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
+
+       /*
+        * only wait on non-file metadata writeback (the mds
+        * can recover size and mtime, so we don't need to
+        * wait for that)
+        */
+       if (!datasync && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
+               dout("fsync waiting for flush_tid %u\n", flush_tid);
+               ret = wait_event_interruptible(ci->i_cap_wq,
+                                      caps_are_flushed(inode, flush_tid));
+       }
+
+       dout("fsync %p%s done\n", inode, datasync ? " datasync" : "");
+       return ret;
+}
+
+/*
+ * Flush any dirty caps back to the mds.  If we aren't asked to wait,
+ * queue inode for flush but don't do so immediately, because we can
+ * get by with fewer MDS messages if we wait for data writeback to
+ * complete first.
+ */
+int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       unsigned flush_tid;
+       int err = 0;
+       int dirty;
+       int wait = wbc->sync_mode == WB_SYNC_ALL;
+
+       dout("write_inode %p wait=%d\n", inode, wait);
+       if (wait) {
+               dirty = try_flush_caps(inode, NULL, &flush_tid);
+               if (dirty)
+                       err = wait_event_interruptible(ci->i_cap_wq,
+                                      caps_are_flushed(inode, flush_tid));
+       } else {
+               struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+
+               spin_lock(&inode->i_lock);
+               if (__ceph_caps_dirty(ci))
+                       __cap_delay_requeue_front(mdsc, ci);
+               spin_unlock(&inode->i_lock);
+       }
+       return err;
+}
+
+/*
+ * After a recovering MDS goes active, we need to resend any caps
+ * we were flushing.
+ *
+ * Caller holds session->s_mutex.
+ */
+static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
+                                  struct ceph_mds_session *session)
+{
+       struct ceph_cap_snap *capsnap;
+
+       dout("kick_flushing_capsnaps mds%d\n", session->s_mds);
+       list_for_each_entry(capsnap, &session->s_cap_snaps_flushing,
+                           flushing_item) {
+               struct ceph_inode_info *ci = capsnap->ci;
+               struct inode *inode = &ci->vfs_inode;
+               struct ceph_cap *cap;
+
+               spin_lock(&inode->i_lock);
+               cap = ci->i_auth_cap;
+               if (cap && cap->session == session) {
+                       dout("kick_flushing_caps %p cap %p capsnap %p\n", inode,
+                            cap, capsnap);
+                       __ceph_flush_snaps(ci, &session);
+               } else {
+                       pr_err("%p auth cap %p not mds%d ???\n", inode,
+                              cap, session->s_mds);
+                       spin_unlock(&inode->i_lock);
+               }
+       }
+}
+
+void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
+                            struct ceph_mds_session *session)
+{
+       struct ceph_inode_info *ci;
+
+       kick_flushing_capsnaps(mdsc, session);
+
+       dout("kick_flushing_caps mds%d\n", session->s_mds);
+       list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
+               struct inode *inode = &ci->vfs_inode;
+               struct ceph_cap *cap;
+               int delayed = 0;
+
+               spin_lock(&inode->i_lock);
+               cap = ci->i_auth_cap;
+               if (cap && cap->session == session) {
+                       dout("kick_flushing_caps %p cap %p %s\n", inode,
+                            cap, ceph_cap_string(ci->i_flushing_caps));
+                       delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                                            __ceph_caps_used(ci),
+                                            __ceph_caps_wanted(ci),
+                                            cap->issued | cap->implemented,
+                                            ci->i_flushing_caps, NULL);
+                       if (delayed) {
+                               spin_lock(&inode->i_lock);
+                               __cap_delay_requeue(mdsc, ci);
+                               spin_unlock(&inode->i_lock);
+                       }
+               } else {
+                       pr_err("%p auth cap %p not mds%d ???\n", inode,
+                              cap, session->s_mds);
+                       spin_unlock(&inode->i_lock);
+               }
+       }
+}
+
+
+/*
+ * Take references to capabilities we hold, so that we don't release
+ * them to the MDS prematurely.
+ *
+ * Protected by i_lock.
+ */
+static void __take_cap_refs(struct ceph_inode_info *ci, int got)
+{
+       if (got & CEPH_CAP_PIN)
+               ci->i_pin_ref++;
+       if (got & CEPH_CAP_FILE_RD)
+               ci->i_rd_ref++;
+       if (got & CEPH_CAP_FILE_CACHE)
+               ci->i_rdcache_ref++;
+       if (got & CEPH_CAP_FILE_WR)
+               ci->i_wr_ref++;
+       if (got & CEPH_CAP_FILE_BUFFER) {
+               if (ci->i_wrbuffer_ref == 0)
+                       igrab(&ci->vfs_inode);
+               ci->i_wrbuffer_ref++;
+               dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n",
+                    &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref);
+       }
+}
+
+/*
+ * Try to grab cap references.  Specify those refs we @want, and the
+ * minimal set we @need.  Also include the larger offset we are writing
+ * to (when applicable), and check against max_size here as well.
+ * Note that caller is responsible for ensuring max_size increases are
+ * requested from the MDS.
+ */
+static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
+                           int *got, loff_t endoff, int *check_max, int *err)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int ret = 0;
+       int have, implemented;
+       int file_wanted;
+
+       dout("get_cap_refs %p need %s want %s\n", inode,
+            ceph_cap_string(need), ceph_cap_string(want));
+       spin_lock(&inode->i_lock);
+
+       /* make sure file is actually open */
+       file_wanted = __ceph_caps_file_wanted(ci);
+       if ((file_wanted & need) == 0) {
+               dout("try_get_cap_refs need %s file_wanted %s, EBADF\n",
+                    ceph_cap_string(need), ceph_cap_string(file_wanted));
+               *err = -EBADF;
+               ret = 1;
+               goto out;
+       }
+
+       if (need & CEPH_CAP_FILE_WR) {
+               if (endoff >= 0 && endoff > (loff_t)ci->i_max_size) {
+                       dout("get_cap_refs %p endoff %llu > maxsize %llu\n",
+                            inode, endoff, ci->i_max_size);
+                       if (endoff > ci->i_wanted_max_size) {
+                               *check_max = 1;
+                               ret = 1;
+                       }
+                       goto out;
+               }
+               /*
+                * If a sync write is in progress, we must wait, so that we
+                * can get a final snapshot value for size+mtime.
+                */
+               if (__ceph_have_pending_cap_snap(ci)) {
+                       dout("get_cap_refs %p cap_snap_pending\n", inode);
+                       goto out;
+               }
+       }
+       have = __ceph_caps_issued(ci, &implemented);
+
+       /*
+        * disallow writes while a truncate is pending
+        */
+       if (ci->i_truncate_pending)
+               have &= ~CEPH_CAP_FILE_WR;
+
+       if ((have & need) == need) {
+               /*
+                * Look at (implemented & ~have & not) so that we keep waiting
+                * on transition from wanted -> needed caps.  This is needed
+                * for WRBUFFER|WR -> WR to avoid a new WR sync write from
+                * going before a prior buffered writeback happens.
+                */
+               int not = want & ~(have & need);
+               int revoking = implemented & ~have;
+               dout("get_cap_refs %p have %s but not %s (revoking %s)\n",
+                    inode, ceph_cap_string(have), ceph_cap_string(not),
+                    ceph_cap_string(revoking));
+               if ((revoking & not) == 0) {
+                       *got = need | (have & want);
+                       __take_cap_refs(ci, *got);
+                       ret = 1;
+               }
+       } else {
+               dout("get_cap_refs %p have %s needed %s\n", inode,
+                    ceph_cap_string(have), ceph_cap_string(need));
+       }
+out:
+       spin_unlock(&inode->i_lock);
+       dout("get_cap_refs %p ret %d got %s\n", inode,
+            ret, ceph_cap_string(*got));
+       return ret;
+}
+
+/*
+ * Check the offset we are writing up to against our current
+ * max_size.  If necessary, tell the MDS we want to write to
+ * a larger offset.
+ */
+static void check_max_size(struct inode *inode, loff_t endoff)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int check = 0;
+
+       /* do we need to explicitly request a larger max_size? */
+       spin_lock(&inode->i_lock);
+       if ((endoff >= ci->i_max_size ||
+            endoff > (inode->i_size << 1)) &&
+           endoff > ci->i_wanted_max_size) {
+               dout("write %p at large endoff %llu, req max_size\n",
+                    inode, endoff);
+               ci->i_wanted_max_size = endoff;
+               check = 1;
+       }
+       spin_unlock(&inode->i_lock);
+       if (check)
+               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+}
+
+/*
+ * Wait for caps, and take cap references.  If we can't get a WR cap
+ * due to a small max_size, make sure we check_max_size (and possibly
+ * ask the mds) so we don't get hung up indefinitely.
+ */
+int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, int *got,
+                 loff_t endoff)
+{
+       int check_max, ret, err;
+
+retry:
+       if (endoff > 0)
+               check_max_size(&ci->vfs_inode, endoff);
+       check_max = 0;
+       err = 0;
+       ret = wait_event_interruptible(ci->i_cap_wq,
+                                      try_get_cap_refs(ci, need, want,
+                                                       got, endoff,
+                                                       &check_max, &err));
+       if (err)
+               ret = err;
+       if (check_max)
+               goto retry;
+       return ret;
+}
+
+/*
+ * Take cap refs.  Caller must already know we hold at least one ref
+ * on the caps in question or we don't know this is safe.
+ */
+void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps)
+{
+       spin_lock(&ci->vfs_inode.i_lock);
+       __take_cap_refs(ci, caps);
+       spin_unlock(&ci->vfs_inode.i_lock);
+}
+
+/*
+ * Release cap refs.
+ *
+ * If we released the last ref on any given cap, call ceph_check_caps
+ * to release (or schedule a release).
+ *
+ * If we are releasing a WR cap (from a sync write), finalize any affected
+ * cap_snap, and wake up any waiters.
+ */
+void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int last = 0, put = 0, flushsnaps = 0, wake = 0;
+       struct ceph_cap_snap *capsnap;
+
+       spin_lock(&inode->i_lock);
+       if (had & CEPH_CAP_PIN)
+               --ci->i_pin_ref;
+       if (had & CEPH_CAP_FILE_RD)
+               if (--ci->i_rd_ref == 0)
+                       last++;
+       if (had & CEPH_CAP_FILE_CACHE)
+               if (--ci->i_rdcache_ref == 0)
+                       last++;
+       if (had & CEPH_CAP_FILE_BUFFER) {
+               if (--ci->i_wrbuffer_ref == 0) {
+                       last++;
+                       put++;
+               }
+               dout("put_cap_refs %p wrbuffer %d -> %d (?)\n",
+                    inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref);
+       }
+       if (had & CEPH_CAP_FILE_WR)
+               if (--ci->i_wr_ref == 0) {
+                       last++;
+                       if (!list_empty(&ci->i_cap_snaps)) {
+                               capsnap = list_first_entry(&ci->i_cap_snaps,
+                                                    struct ceph_cap_snap,
+                                                    ci_item);
+                               if (capsnap->writing) {
+                                       capsnap->writing = 0;
+                                       flushsnaps =
+                                               __ceph_finish_cap_snap(ci,
+                                                                      capsnap);
+                                       wake = 1;
+                               }
+                       }
+               }
+       spin_unlock(&inode->i_lock);
+
+       dout("put_cap_refs %p had %s %s\n", inode, ceph_cap_string(had),
+            last ? "last" : "");
+
+       if (last && !flushsnaps)
+               ceph_check_caps(ci, 0, NULL);
+       else if (flushsnaps)
+               ceph_flush_snaps(ci);
+       if (wake)
+               wake_up(&ci->i_cap_wq);
+       if (put)
+               iput(inode);
+}
+
+/*
+ * Release @nr WRBUFFER refs on dirty pages for the given @snapc snap
+ * context.  Adjust per-snap dirty page accounting as appropriate.
+ * Once all dirty data for a cap_snap is flushed, flush snapped file
+ * metadata back to the MDS.  If we dropped the last ref, call
+ * ceph_check_caps.
+ */
+void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
+                               struct ceph_snap_context *snapc)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int last = 0;
+       int last_snap = 0;
+       int found = 0;
+       struct ceph_cap_snap *capsnap = NULL;
+
+       spin_lock(&inode->i_lock);
+       ci->i_wrbuffer_ref -= nr;
+       last = !ci->i_wrbuffer_ref;
+
+       if (ci->i_head_snapc == snapc) {
+               ci->i_wrbuffer_ref_head -= nr;
+               if (!ci->i_wrbuffer_ref_head) {
+                       ceph_put_snap_context(ci->i_head_snapc);
+                       ci->i_head_snapc = NULL;
+               }
+               dout("put_wrbuffer_cap_refs on %p head %d/%d -> %d/%d %s\n",
+                    inode,
+                    ci->i_wrbuffer_ref+nr, ci->i_wrbuffer_ref_head+nr,
+                    ci->i_wrbuffer_ref, ci->i_wrbuffer_ref_head,
+                    last ? " LAST" : "");
+       } else {
+               list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+                       if (capsnap->context == snapc) {
+                               found = 1;
+                               capsnap->dirty_pages -= nr;
+                               last_snap = !capsnap->dirty_pages;
+                               break;
+                       }
+               }
+               BUG_ON(!found);
+               dout("put_wrbuffer_cap_refs on %p cap_snap %p "
+                    " snap %lld %d/%d -> %d/%d %s%s\n",
+                    inode, capsnap, capsnap->context->seq,
+                    ci->i_wrbuffer_ref+nr, capsnap->dirty_pages + nr,
+                    ci->i_wrbuffer_ref, capsnap->dirty_pages,
+                    last ? " (wrbuffer last)" : "",
+                    last_snap ? " (capsnap last)" : "");
+       }
+
+       spin_unlock(&inode->i_lock);
+
+       if (last) {
+               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+               iput(inode);
+       } else if (last_snap) {
+               ceph_flush_snaps(ci);
+               wake_up(&ci->i_cap_wq);
+       }
+}
+
+/*
+ * Handle a cap GRANT message from the MDS.  (Note that a GRANT may
+ * actually be a revocation if it specifies a smaller cap set.)
+ *
+ * caller holds s_mutex.
+ * return value:
+ *  0 - ok
+ *  1 - check_caps on auth cap only (writeback)
+ *  2 - check_caps (ack revoke)
+ */
+static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
+                           struct ceph_mds_session *session,
+                           struct ceph_cap *cap,
+                           struct ceph_buffer *xattr_buf)
+       __releases(inode->i_lock)
+
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int mds = session->s_mds;
+       int seq = le32_to_cpu(grant->seq);
+       int newcaps = le32_to_cpu(grant->caps);
+       int issued, implemented, used, wanted, dirty;
+       u64 size = le64_to_cpu(grant->size);
+       u64 max_size = le64_to_cpu(grant->max_size);
+       struct timespec mtime, atime, ctime;
+       int reply = 0;
+       int wake = 0;
+       int writeback = 0;
+       int revoked_rdcache = 0;
+       int queue_invalidate = 0;
+
+       dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
+            inode, cap, mds, seq, ceph_cap_string(newcaps));
+       dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
+               inode->i_size);
+
+       /*
+        * If CACHE is being revoked, and we have no dirty buffers,
+        * try to invalidate (once).  (If there are dirty buffers, we
+        * will invalidate _after_ writeback.)
+        */
+       if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
+           !ci->i_wrbuffer_ref) {
+               if (try_nonblocking_invalidate(inode) == 0) {
+                       revoked_rdcache = 1;
+               } else {
+                       /* there were locked pages.. invalidate later
+                          in a separate thread. */
+                       if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
+                               queue_invalidate = 1;
+                               ci->i_rdcache_revoking = ci->i_rdcache_gen;
+                       }
+               }
+       }
+
+       /* side effects now are allowed */
+
+       issued = __ceph_caps_issued(ci, &implemented);
+       issued |= implemented | __ceph_caps_dirty(ci);
+
+       cap->cap_gen = session->s_cap_gen;
+
+       __check_cap_issue(ci, cap, newcaps);
+
+       if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {
+               inode->i_mode = le32_to_cpu(grant->mode);
+               inode->i_uid = le32_to_cpu(grant->uid);
+               inode->i_gid = le32_to_cpu(grant->gid);
+               dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
+                    inode->i_uid, inode->i_gid);
+       }
+
+       if ((issued & CEPH_CAP_LINK_EXCL) == 0)
+               inode->i_nlink = le32_to_cpu(grant->nlink);
+
+       if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
+               int len = le32_to_cpu(grant->xattr_len);
+               u64 version = le64_to_cpu(grant->xattr_version);
+
+               if (version > ci->i_xattrs.version) {
+                       dout(" got new xattrs v%llu on %p len %d\n",
+                            version, inode, len);
+                       if (ci->i_xattrs.blob)
+                               ceph_buffer_put(ci->i_xattrs.blob);
+                       ci->i_xattrs.blob = ceph_buffer_get(xattr_buf);
+                       ci->i_xattrs.version = version;
+               }
+       }
+
+       /* size/ctime/mtime/atime? */
+       ceph_fill_file_size(inode, issued,
+                           le32_to_cpu(grant->truncate_seq),
+                           le64_to_cpu(grant->truncate_size), size);
+       ceph_decode_timespec(&mtime, &grant->mtime);
+       ceph_decode_timespec(&atime, &grant->atime);
+       ceph_decode_timespec(&ctime, &grant->ctime);
+       ceph_fill_file_time(inode, issued,
+                           le32_to_cpu(grant->time_warp_seq), &ctime, &mtime,
+                           &atime);
+
+       /* max size increase? */
+       if (max_size != ci->i_max_size) {
+               dout("max_size %lld -> %llu\n", ci->i_max_size, max_size);
+               ci->i_max_size = max_size;
+               if (max_size >= ci->i_wanted_max_size) {
+                       ci->i_wanted_max_size = 0;  /* reset */
+                       ci->i_requested_max_size = 0;
+               }
+               wake = 1;
+       }
+
+       /* check cap bits */
+       wanted = __ceph_caps_wanted(ci);
+       used = __ceph_caps_used(ci);
+       dirty = __ceph_caps_dirty(ci);
+       dout(" my wanted = %s, used = %s, dirty %s\n",
+            ceph_cap_string(wanted),
+            ceph_cap_string(used),
+            ceph_cap_string(dirty));
+       if (wanted != le32_to_cpu(grant->wanted)) {
+               dout("mds wanted %s -> %s\n",
+                    ceph_cap_string(le32_to_cpu(grant->wanted)),
+                    ceph_cap_string(wanted));
+               grant->wanted = cpu_to_le32(wanted);
+       }
+
+       cap->seq = seq;
+
+       /* file layout may have changed */
+       ci->i_layout = grant->layout;
+
+       /* revocation, grant, or no-op? */
+       if (cap->issued & ~newcaps) {
+               dout("revocation: %s -> %s\n", ceph_cap_string(cap->issued),
+                    ceph_cap_string(newcaps));
+               if ((used & ~newcaps) & CEPH_CAP_FILE_BUFFER)
+                       writeback = 1; /* will delay ack */
+               else if (dirty & ~newcaps)
+                       reply = 1;     /* initiate writeback in check_caps */
+               else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 ||
+                          revoked_rdcache)
+                       reply = 2;     /* send revoke ack in check_caps */
+               cap->issued = newcaps;
+       } else if (cap->issued == newcaps) {
+               dout("caps unchanged: %s -> %s\n",
+                    ceph_cap_string(cap->issued), ceph_cap_string(newcaps));
+       } else {
+               dout("grant: %s -> %s\n", ceph_cap_string(cap->issued),
+                    ceph_cap_string(newcaps));
+               cap->issued = newcaps;
+               cap->implemented |= newcaps; /* add bits only, to
+                                             * avoid stepping on a
+                                             * pending revocation */
+               wake = 1;
+       }
+
+       spin_unlock(&inode->i_lock);
+       if (writeback)
+               /*
+                * queue inode for writeback: we can't actually call
+                * filemap_write_and_wait, etc. from message handler
+                * context.
+                */
+               ceph_queue_writeback(inode);
+       if (queue_invalidate)
+               ceph_queue_invalidate(inode);
+       if (wake)
+               wake_up(&ci->i_cap_wq);
+       return reply;
+}
+
+/*
+ * Handle FLUSH_ACK from MDS, indicating that metadata we sent to the
+ * MDS has been safely committed.
+ */
+static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
+                                struct ceph_mds_caps *m,
+                                struct ceph_mds_session *session,
+                                struct ceph_cap *cap)
+       __releases(inode->i_lock)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+       unsigned seq = le32_to_cpu(m->seq);
+       int dirty = le32_to_cpu(m->dirty);
+       int cleaned = 0;
+       int drop = 0;
+       int i;
+
+       for (i = 0; i < CEPH_CAP_BITS; i++)
+               if ((dirty & (1 << i)) &&
+                   flush_tid == ci->i_cap_flush_tid[i])
+                       cleaned |= 1 << i;
+
+       dout("handle_cap_flush_ack inode %p mds%d seq %d on %s cleaned %s,"
+            " flushing %s -> %s\n",
+            inode, session->s_mds, seq, ceph_cap_string(dirty),
+            ceph_cap_string(cleaned), ceph_cap_string(ci->i_flushing_caps),
+            ceph_cap_string(ci->i_flushing_caps & ~cleaned));
+
+       if (ci->i_flushing_caps == (ci->i_flushing_caps & ~cleaned))
+               goto out;
+
+       ci->i_flushing_caps &= ~cleaned;
+
+       spin_lock(&mdsc->cap_dirty_lock);
+       if (ci->i_flushing_caps == 0) {
+               list_del_init(&ci->i_flushing_item);
+               if (!list_empty(&session->s_cap_flushing))
+                       dout(" mds%d still flushing cap on %p\n",
+                            session->s_mds,
+                            &list_entry(session->s_cap_flushing.next,
+                                        struct ceph_inode_info,
+                                        i_flushing_item)->vfs_inode);
+               mdsc->num_cap_flushing--;
+               wake_up(&mdsc->cap_flushing_wq);
+               dout(" inode %p now !flushing\n", inode);
+
+               if (ci->i_dirty_caps == 0) {
+                       dout(" inode %p now clean\n", inode);
+                       BUG_ON(!list_empty(&ci->i_dirty_item));
+                       drop = 1;
+               } else {
+                       BUG_ON(list_empty(&ci->i_dirty_item));
+               }
+       }
+       spin_unlock(&mdsc->cap_dirty_lock);
+       wake_up(&ci->i_cap_wq);
+
+out:
+       spin_unlock(&inode->i_lock);
+       if (drop)
+               iput(inode);
+}
+
+/*
+ * Handle FLUSHSNAP_ACK.  MDS has flushed snap data to disk and we can
+ * throw away our cap_snap.
+ *
+ * Caller hold s_mutex.
+ */
+static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid,
+                                    struct ceph_mds_caps *m,
+                                    struct ceph_mds_session *session)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       u64 follows = le64_to_cpu(m->snap_follows);
+       struct ceph_cap_snap *capsnap;
+       int drop = 0;
+
+       dout("handle_cap_flushsnap_ack inode %p ci %p mds%d follows %lld\n",
+            inode, ci, session->s_mds, follows);
+
+       spin_lock(&inode->i_lock);
+       list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+               if (capsnap->follows == follows) {
+                       if (capsnap->flush_tid != flush_tid) {
+                               dout(" cap_snap %p follows %lld tid %lld !="
+                                    " %lld\n", capsnap, follows,
+                                    flush_tid, capsnap->flush_tid);
+                               break;
+                       }
+                       WARN_ON(capsnap->dirty_pages || capsnap->writing);
+                       dout(" removing cap_snap %p follows %lld\n",
+                            capsnap, follows);
+                       ceph_put_snap_context(capsnap->context);
+                       list_del(&capsnap->ci_item);
+                       list_del(&capsnap->flushing_item);
+                       ceph_put_cap_snap(capsnap);
+                       drop = 1;
+                       break;
+               } else {
+                       dout(" skipping cap_snap %p follows %lld\n",
+                            capsnap, capsnap->follows);
+               }
+       }
+       spin_unlock(&inode->i_lock);
+       if (drop)
+               iput(inode);
+}
+
+/*
+ * Handle TRUNC from MDS, indicating file truncation.
+ *
+ * caller hold s_mutex.
+ */
+static void handle_cap_trunc(struct inode *inode,
+                            struct ceph_mds_caps *trunc,
+                            struct ceph_mds_session *session)
+       __releases(inode->i_lock)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int mds = session->s_mds;
+       int seq = le32_to_cpu(trunc->seq);
+       u32 truncate_seq = le32_to_cpu(trunc->truncate_seq);
+       u64 truncate_size = le64_to_cpu(trunc->truncate_size);
+       u64 size = le64_to_cpu(trunc->size);
+       int implemented = 0;
+       int dirty = __ceph_caps_dirty(ci);
+       int issued = __ceph_caps_issued(ceph_inode(inode), &implemented);
+       int queue_trunc = 0;
+
+       issued |= implemented | dirty;
+
+       dout("handle_cap_trunc inode %p mds%d seq %d to %lld seq %d\n",
+            inode, mds, seq, truncate_size, truncate_seq);
+       queue_trunc = ceph_fill_file_size(inode, issued,
+                                         truncate_seq, truncate_size, size);
+       spin_unlock(&inode->i_lock);
+
+       if (queue_trunc)
+               ceph_queue_vmtruncate(inode);
+}
+
+/*
+ * Handle EXPORT from MDS.  Cap is being migrated _from_ this mds to a
+ * different one.  If we are the most recent migration we've seen (as
+ * indicated by mseq), make note of the migrating cap bits for the
+ * duration (until we see the corresponding IMPORT).
+ *
+ * caller holds s_mutex
+ */
+static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
+                             struct ceph_mds_session *session)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int mds = session->s_mds;
+       unsigned mseq = le32_to_cpu(ex->migrate_seq);
+       struct ceph_cap *cap = NULL, *t;
+       struct rb_node *p;
+       int remember = 1;
+
+       dout("handle_cap_export inode %p ci %p mds%d mseq %d\n",
+            inode, ci, mds, mseq);
+
+       spin_lock(&inode->i_lock);
+
+       /* make sure we haven't seen a higher mseq */
+       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+               t = rb_entry(p, struct ceph_cap, ci_node);
+               if (ceph_seq_cmp(t->mseq, mseq) > 0) {
+                       dout(" higher mseq on cap from mds%d\n",
+                            t->session->s_mds);
+                       remember = 0;
+               }
+               if (t->session->s_mds == mds)
+                       cap = t;
+       }
+
+       if (cap) {
+               if (remember) {
+                       /* make note */
+                       ci->i_cap_exporting_mds = mds;
+                       ci->i_cap_exporting_mseq = mseq;
+                       ci->i_cap_exporting_issued = cap->issued;
+               }
+               __ceph_remove_cap(cap);
+       } else {
+               WARN_ON(!cap);
+       }
+
+       spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Handle cap IMPORT.  If there are temp bits from an older EXPORT,
+ * clean them up.
+ *
+ * caller holds s_mutex.
+ */
+static void handle_cap_import(struct ceph_mds_client *mdsc,
+                             struct inode *inode, struct ceph_mds_caps *im,
+                             struct ceph_mds_session *session,
+                             void *snaptrace, int snaptrace_len)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int mds = session->s_mds;
+       unsigned issued = le32_to_cpu(im->caps);
+       unsigned wanted = le32_to_cpu(im->wanted);
+       unsigned seq = le32_to_cpu(im->seq);
+       unsigned mseq = le32_to_cpu(im->migrate_seq);
+       u64 realmino = le64_to_cpu(im->realm);
+       u64 cap_id = le64_to_cpu(im->cap_id);
+
+       if (ci->i_cap_exporting_mds >= 0 &&
+           ceph_seq_cmp(ci->i_cap_exporting_mseq, mseq) < 0) {
+               dout("handle_cap_import inode %p ci %p mds%d mseq %d"
+                    " - cleared exporting from mds%d\n",
+                    inode, ci, mds, mseq,
+                    ci->i_cap_exporting_mds);
+               ci->i_cap_exporting_issued = 0;
+               ci->i_cap_exporting_mseq = 0;
+               ci->i_cap_exporting_mds = -1;
+       } else {
+               dout("handle_cap_import inode %p ci %p mds%d mseq %d\n",
+                    inode, ci, mds, mseq);
+       }
+
+       down_write(&mdsc->snap_rwsem);
+       ceph_update_snap_trace(mdsc, snaptrace, snaptrace+snaptrace_len,
+                              false);
+       downgrade_write(&mdsc->snap_rwsem);
+       ceph_add_cap(inode, session, cap_id, -1,
+                    issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH,
+                    NULL /* no caps context */);
+       try_flush_caps(inode, session, NULL);
+       up_read(&mdsc->snap_rwsem);
+}
+
+/*
+ * Handle a caps message from the MDS.
+ *
+ * Identify the appropriate session, inode, and call the right handler
+ * based on the cap op.
+ */
+void ceph_handle_caps(struct ceph_mds_session *session,
+                     struct ceph_msg *msg)
+{
+       struct ceph_mds_client *mdsc = session->s_mdsc;
+       struct super_block *sb = mdsc->client->sb;
+       struct inode *inode;
+       struct ceph_cap *cap;
+       struct ceph_mds_caps *h;
+       int mds = session->s_mds;
+       int op;
+       u32 seq;
+       struct ceph_vino vino;
+       u64 cap_id;
+       u64 size, max_size;
+       u64 tid;
+       int check_caps = 0;
+       void *snaptrace;
+       int r;
+
+       dout("handle_caps from mds%d\n", mds);
+
+       /* decode */
+       tid = le64_to_cpu(msg->hdr.tid);
+       if (msg->front.iov_len < sizeof(*h))
+               goto bad;
+       h = msg->front.iov_base;
+       snaptrace = h + 1;
+       op = le32_to_cpu(h->op);
+       vino.ino = le64_to_cpu(h->ino);
+       vino.snap = CEPH_NOSNAP;
+       cap_id = le64_to_cpu(h->cap_id);
+       seq = le32_to_cpu(h->seq);
+       size = le64_to_cpu(h->size);
+       max_size = le64_to_cpu(h->max_size);
+
+       mutex_lock(&session->s_mutex);
+       session->s_seq++;
+       dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq,
+            (unsigned)seq);
+
+       /* lookup ino */
+       inode = ceph_find_inode(sb, vino);
+       dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino,
+            vino.snap, inode);
+       if (!inode) {
+               dout(" i don't have ino %llx\n", vino.ino);
+               goto done;
+       }
+
+       /* these will work even if we don't have a cap yet */
+       switch (op) {
+       case CEPH_CAP_OP_FLUSHSNAP_ACK:
+               handle_cap_flushsnap_ack(inode, tid, h, session);
+               goto done;
+
+       case CEPH_CAP_OP_EXPORT:
+               handle_cap_export(inode, h, session);
+               goto done;
+
+       case CEPH_CAP_OP_IMPORT:
+               handle_cap_import(mdsc, inode, h, session,
+                                 snaptrace, le32_to_cpu(h->snap_trace_len));
+               check_caps = 1; /* we may have sent a RELEASE to the old auth */
+               goto done;
+       }
+
+       /* the rest require a cap */
+       spin_lock(&inode->i_lock);
+       cap = __get_cap_for_mds(ceph_inode(inode), mds);
+       if (!cap) {
+               dout("no cap on %p ino %llx.%llx from mds%d, releasing\n",
+                    inode, ceph_ino(inode), ceph_snap(inode), mds);
+               spin_unlock(&inode->i_lock);
+               goto done;
+       }
+
+       /* note that each of these drops i_lock for us */
+       switch (op) {
+       case CEPH_CAP_OP_REVOKE:
+       case CEPH_CAP_OP_GRANT:
+               r = handle_cap_grant(inode, h, session, cap, msg->middle);
+               if (r == 1)
+                       ceph_check_caps(ceph_inode(inode),
+                                       CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY,
+                                       session);
+               else if (r == 2)
+                       ceph_check_caps(ceph_inode(inode),
+                                       CHECK_CAPS_NODELAY,
+                                       session);
+               break;
+
+       case CEPH_CAP_OP_FLUSH_ACK:
+               handle_cap_flush_ack(inode, tid, h, session, cap);
+               break;
+
+       case CEPH_CAP_OP_TRUNC:
+               handle_cap_trunc(inode, h, session);
+               break;
+
+       default:
+               spin_unlock(&inode->i_lock);
+               pr_err("ceph_handle_caps: unknown cap op %d %s\n", op,
+                      ceph_cap_op_name(op));
+       }
+
+done:
+       mutex_unlock(&session->s_mutex);
+
+       if (check_caps)
+               ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL);
+       if (inode)
+               iput(inode);
+       return;
+
+bad:
+       pr_err("ceph_handle_caps: corrupt message\n");
+       ceph_msg_dump(msg);
+       return;
+}
+
+/*
+ * Delayed work handler to process end of delayed cap release LRU list.
+ */
+void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
+{
+       struct ceph_inode_info *ci;
+       int flags = CHECK_CAPS_NODELAY;
+
+       dout("check_delayed_caps\n");
+       while (1) {
+               spin_lock(&mdsc->cap_delay_lock);
+               if (list_empty(&mdsc->cap_delay_list))
+                       break;
+               ci = list_first_entry(&mdsc->cap_delay_list,
+                                     struct ceph_inode_info,
+                                     i_cap_delay_list);
+               if ((ci->i_ceph_flags & CEPH_I_FLUSH) == 0 &&
+                   time_before(jiffies, ci->i_hold_caps_max))
+                       break;
+               list_del_init(&ci->i_cap_delay_list);
+               spin_unlock(&mdsc->cap_delay_lock);
+               dout("check_delayed_caps on %p\n", &ci->vfs_inode);
+               ceph_check_caps(ci, flags, NULL);
+       }
+       spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Flush all dirty caps to the mds
+ */
+void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
+{
+       struct ceph_inode_info *ci, *nci = NULL;
+       struct inode *inode, *ninode = NULL;
+       struct list_head *p, *n;
+
+       dout("flush_dirty_caps\n");
+       spin_lock(&mdsc->cap_dirty_lock);
+       list_for_each_safe(p, n, &mdsc->cap_dirty) {
+               if (nci) {
+                       ci = nci;
+                       inode = ninode;
+                       ci->i_ceph_flags &= ~CEPH_I_NOFLUSH;
+                       dout("flush_dirty_caps inode %p (was next inode)\n",
+                            inode);
+               } else {
+                       ci = list_entry(p, struct ceph_inode_info,
+                                       i_dirty_item);
+                       inode = igrab(&ci->vfs_inode);
+                       BUG_ON(!inode);
+                       dout("flush_dirty_caps inode %p\n", inode);
+               }
+               if (n != &mdsc->cap_dirty) {
+                       nci = list_entry(n, struct ceph_inode_info,
+                                        i_dirty_item);
+                       ninode = igrab(&nci->vfs_inode);
+                       BUG_ON(!ninode);
+                       nci->i_ceph_flags |= CEPH_I_NOFLUSH;
+                       dout("flush_dirty_caps next inode %p, noflush\n",
+                            ninode);
+               } else {
+                       nci = NULL;
+                       ninode = NULL;
+               }
+               spin_unlock(&mdsc->cap_dirty_lock);
+               if (inode) {
+                       ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH,
+                                       NULL);
+                       iput(inode);
+               }
+               spin_lock(&mdsc->cap_dirty_lock);
+       }
+       spin_unlock(&mdsc->cap_dirty_lock);
+}
+
+/*
+ * Drop open file reference.  If we were the last open file,
+ * we may need to release capabilities to the MDS (or schedule
+ * their delayed release).
+ */
+void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int last = 0;
+
+       spin_lock(&inode->i_lock);
+       dout("put_fmode %p fmode %d %d -> %d\n", inode, fmode,
+            ci->i_nr_by_mode[fmode], ci->i_nr_by_mode[fmode]-1);
+       BUG_ON(ci->i_nr_by_mode[fmode] == 0);
+       if (--ci->i_nr_by_mode[fmode] == 0)
+               last++;
+       spin_unlock(&inode->i_lock);
+
+       if (last && ci->i_vino.snap == CEPH_NOSNAP)
+               ceph_check_caps(ci, 0, NULL);
+}
+
+/*
+ * Helpers for embedding cap and dentry lease releases into mds
+ * requests.
+ *
+ * @force is used by dentry_release (below) to force inclusion of a
+ * record for the directory inode, even when there aren't any caps to
+ * drop.
+ */
+int ceph_encode_inode_release(void **p, struct inode *inode,
+                             int mds, int drop, int unless, int force)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap *cap;
+       struct ceph_mds_request_release *rel = *p;
+       int ret = 0;
+
+       dout("encode_inode_release %p mds%d drop %s unless %s\n", inode,
+            mds, ceph_cap_string(drop), ceph_cap_string(unless));
+
+       spin_lock(&inode->i_lock);
+       cap = __get_cap_for_mds(ci, mds);
+       if (cap && __cap_is_valid(cap)) {
+               if (force ||
+                   ((cap->issued & drop) &&
+                    (cap->issued & unless) == 0)) {
+                       if ((cap->issued & drop) &&
+                           (cap->issued & unless) == 0) {
+                               dout("encode_inode_release %p cap %p %s -> "
+                                    "%s\n", inode, cap,
+                                    ceph_cap_string(cap->issued),
+                                    ceph_cap_string(cap->issued & ~drop));
+                               cap->issued &= ~drop;
+                               cap->implemented &= ~drop;
+                               if (ci->i_ceph_flags & CEPH_I_NODELAY) {
+                                       int wanted = __ceph_caps_wanted(ci);
+                                       dout("  wanted %s -> %s (act %s)\n",
+                                            ceph_cap_string(cap->mds_wanted),
+                                            ceph_cap_string(cap->mds_wanted &
+                                                            ~wanted),
+                                            ceph_cap_string(wanted));
+                                       cap->mds_wanted &= wanted;
+                               }
+                       } else {
+                               dout("encode_inode_release %p cap %p %s"
+                                    " (force)\n", inode, cap,
+                                    ceph_cap_string(cap->issued));
+                       }
+
+                       rel->ino = cpu_to_le64(ceph_ino(inode));
+                       rel->cap_id = cpu_to_le64(cap->cap_id);
+                       rel->seq = cpu_to_le32(cap->seq);
+                       rel->issue_seq = cpu_to_le32(cap->issue_seq),
+                       rel->mseq = cpu_to_le32(cap->mseq);
+                       rel->caps = cpu_to_le32(cap->issued);
+                       rel->wanted = cpu_to_le32(cap->mds_wanted);
+                       rel->dname_len = 0;
+                       rel->dname_seq = 0;
+                       *p += sizeof(*rel);
+                       ret = 1;
+               } else {
+                       dout("encode_inode_release %p cap %p %s\n",
+                            inode, cap, ceph_cap_string(cap->issued));
+               }
+       }
+       spin_unlock(&inode->i_lock);
+       return ret;
+}
+
+int ceph_encode_dentry_release(void **p, struct dentry *dentry,
+                              int mds, int drop, int unless)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+       struct ceph_mds_request_release *rel = *p;
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+       int force = 0;
+       int ret;
+
+       /*
+        * force an record for the directory caps if we have a dentry lease.
+        * this is racy (can't take i_lock and d_lock together), but it
+        * doesn't have to be perfect; the mds will revoke anything we don't
+        * release.
+        */
+       spin_lock(&dentry->d_lock);
+       if (di->lease_session && di->lease_session->s_mds == mds)
+               force = 1;
+       spin_unlock(&dentry->d_lock);
+
+       ret = ceph_encode_inode_release(p, dir, mds, drop, unless, force);
+
+       spin_lock(&dentry->d_lock);
+       if (ret && di->lease_session && di->lease_session->s_mds == mds) {
+               dout("encode_dentry_release %p mds%d seq %d\n",
+                    dentry, mds, (int)di->lease_seq);
+               rel->dname_len = cpu_to_le32(dentry->d_name.len);
+               memcpy(*p, dentry->d_name.name, dentry->d_name.len);
+               *p += dentry->d_name.len;
+               rel->dname_seq = cpu_to_le32(di->lease_seq);
+       }
+       spin_unlock(&dentry->d_lock);
+       return ret;
+}
diff --git a/fs/ceph/ceph_debug.h b/fs/ceph/ceph_debug.h
new file mode 100644 (file)
index 0000000..1818c23
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _FS_CEPH_DEBUG_H
+#define _FS_CEPH_DEBUG_H
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#ifdef CONFIG_CEPH_FS_PRETTYDEBUG
+
+/*
+ * wrap pr_debug to include a filename:lineno prefix on each line.
+ * this incurs some overhead (kernel size and execution time) due to
+ * the extra function call at each call site.
+ */
+
+# if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
+extern const char *ceph_file_part(const char *s, int len);
+#  define dout(fmt, ...)                                               \
+       pr_debug(" %12.12s:%-4d : " fmt,                                \
+                ceph_file_part(__FILE__, sizeof(__FILE__)),            \
+                __LINE__, ##__VA_ARGS__)
+# else
+/* faux printk call just to see any compiler warnings. */
+#  define dout(fmt, ...)       do {                            \
+               if (0)                                          \
+                       printk(KERN_DEBUG fmt, ##__VA_ARGS__);  \
+       } while (0)
+# endif
+
+#else
+
+/*
+ * or, just wrap pr_debug
+ */
+# define dout(fmt, ...)        pr_debug(" " fmt, ##__VA_ARGS__)
+
+#endif
+
+#endif
diff --git a/fs/ceph/ceph_frag.c b/fs/ceph/ceph_frag.c
new file mode 100644 (file)
index 0000000..ab6cf35
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Ceph 'frag' type
+ */
+#include "types.h"
+
+int ceph_frag_compare(__u32 a, __u32 b)
+{
+       unsigned va = ceph_frag_value(a);
+       unsigned vb = ceph_frag_value(b);
+       if (va < vb)
+               return -1;
+       if (va > vb)
+               return 1;
+       va = ceph_frag_bits(a);
+       vb = ceph_frag_bits(b);
+       if (va < vb)
+               return -1;
+       if (va > vb)
+               return 1;
+       return 0;
+}
diff --git a/fs/ceph/ceph_frag.h b/fs/ceph/ceph_frag.h
new file mode 100644 (file)
index 0000000..793f50c
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _FS_CEPH_FRAG_H
+#define _FS_CEPH_FRAG_H
+
+/*
+ * "Frags" are a way to describe a subset of a 32-bit number space,
+ * using a mask and a value to match against that mask.  Any given frag
+ * (subset of the number space) can be partitioned into 2^n sub-frags.
+ *
+ * Frags are encoded into a 32-bit word:
+ *   8 upper bits = "bits"
+ *  24 lower bits = "value"
+ * (We could go to 5+27 bits, but who cares.)
+ *
+ * We use the _most_ significant bits of the 24 bit value.  This makes
+ * values logically sort.
+ *
+ * Unfortunately, because the "bits" field is still in the high bits, we
+ * can't sort encoded frags numerically.  However, it does allow you
+ * to feed encoded frags as values into frag_contains_value.
+ */
+static inline __u32 ceph_frag_make(__u32 b, __u32 v)
+{
+       return (b << 24) |
+               (v & (0xffffffu << (24-b)) & 0xffffffu);
+}
+static inline __u32 ceph_frag_bits(__u32 f)
+{
+       return f >> 24;
+}
+static inline __u32 ceph_frag_value(__u32 f)
+{
+       return f & 0xffffffu;
+}
+static inline __u32 ceph_frag_mask(__u32 f)
+{
+       return (0xffffffu << (24-ceph_frag_bits(f))) & 0xffffffu;
+}
+static inline __u32 ceph_frag_mask_shift(__u32 f)
+{
+       return 24 - ceph_frag_bits(f);
+}
+
+static inline int ceph_frag_contains_value(__u32 f, __u32 v)
+{
+       return (v & ceph_frag_mask(f)) == ceph_frag_value(f);
+}
+static inline int ceph_frag_contains_frag(__u32 f, __u32 sub)
+{
+       /* is sub as specific as us, and contained by us? */
+       return ceph_frag_bits(sub) >= ceph_frag_bits(f) &&
+              (ceph_frag_value(sub) & ceph_frag_mask(f)) == ceph_frag_value(f);
+}
+
+static inline __u32 ceph_frag_parent(__u32 f)
+{
+       return ceph_frag_make(ceph_frag_bits(f) - 1,
+                        ceph_frag_value(f) & (ceph_frag_mask(f) << 1));
+}
+static inline int ceph_frag_is_left_child(__u32 f)
+{
+       return ceph_frag_bits(f) > 0 &&
+               (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 0;
+}
+static inline int ceph_frag_is_right_child(__u32 f)
+{
+       return ceph_frag_bits(f) > 0 &&
+               (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 1;
+}
+static inline __u32 ceph_frag_sibling(__u32 f)
+{
+       return ceph_frag_make(ceph_frag_bits(f),
+                     ceph_frag_value(f) ^ (0x1000000 >> ceph_frag_bits(f)));
+}
+static inline __u32 ceph_frag_left_child(__u32 f)
+{
+       return ceph_frag_make(ceph_frag_bits(f)+1, ceph_frag_value(f));
+}
+static inline __u32 ceph_frag_right_child(__u32 f)
+{
+       return ceph_frag_make(ceph_frag_bits(f)+1,
+             ceph_frag_value(f) | (0x1000000 >> (1+ceph_frag_bits(f))));
+}
+static inline __u32 ceph_frag_make_child(__u32 f, int by, int i)
+{
+       int newbits = ceph_frag_bits(f) + by;
+       return ceph_frag_make(newbits,
+                        ceph_frag_value(f) | (i << (24 - newbits)));
+}
+static inline int ceph_frag_is_leftmost(__u32 f)
+{
+       return ceph_frag_value(f) == 0;
+}
+static inline int ceph_frag_is_rightmost(__u32 f)
+{
+       return ceph_frag_value(f) == ceph_frag_mask(f);
+}
+static inline __u32 ceph_frag_next(__u32 f)
+{
+       return ceph_frag_make(ceph_frag_bits(f),
+                        ceph_frag_value(f) + (0x1000000 >> ceph_frag_bits(f)));
+}
+
+/*
+ * comparator to sort frags logically, as when traversing the
+ * number space in ascending order...
+ */
+int ceph_frag_compare(__u32 a, __u32 b);
+
+#endif
diff --git a/fs/ceph/ceph_fs.c b/fs/ceph/ceph_fs.c
new file mode 100644 (file)
index 0000000..79d76bc
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Some non-inline ceph helpers
+ */
+#include "types.h"
+
+/*
+ * return true if @layout appears to be valid
+ */
+int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
+{
+       __u32 su = le32_to_cpu(layout->fl_stripe_unit);
+       __u32 sc = le32_to_cpu(layout->fl_stripe_count);
+       __u32 os = le32_to_cpu(layout->fl_object_size);
+
+       /* stripe unit, object size must be non-zero, 64k increment */
+       if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1)))
+               return 0;
+       if (!os || (os & (CEPH_MIN_STRIPE_UNIT-1)))
+               return 0;
+       /* object size must be a multiple of stripe unit */
+       if (os < su || os % su)
+               return 0;
+       /* stripe count must be non-zero */
+       if (!sc)
+               return 0;
+       return 1;
+}
+
+
+int ceph_flags_to_mode(int flags)
+{
+#ifdef O_DIRECTORY  /* fixme */
+       if ((flags & O_DIRECTORY) == O_DIRECTORY)
+               return CEPH_FILE_MODE_PIN;
+#endif
+#ifdef O_LAZY
+       if (flags & O_LAZY)
+               return CEPH_FILE_MODE_LAZY;
+#endif
+       if ((flags & O_APPEND) == O_APPEND)
+               flags |= O_WRONLY;
+
+       flags &= O_ACCMODE;
+       if ((flags & O_RDWR) == O_RDWR)
+               return CEPH_FILE_MODE_RDWR;
+       if ((flags & O_WRONLY) == O_WRONLY)
+               return CEPH_FILE_MODE_WR;
+       return CEPH_FILE_MODE_RD;
+}
+
+int ceph_caps_for_mode(int mode)
+{
+       switch (mode) {
+       case CEPH_FILE_MODE_PIN:
+               return CEPH_CAP_PIN;
+       case CEPH_FILE_MODE_RD:
+               return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+                       CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE;
+       case CEPH_FILE_MODE_RDWR:
+               return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+                       CEPH_CAP_FILE_EXCL |
+                       CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE |
+                       CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
+                       CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
+                       CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
+       case CEPH_FILE_MODE_WR:
+               return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+                       CEPH_CAP_FILE_EXCL |
+                       CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
+                       CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
+                       CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
+       }
+       return 0;
+}
diff --git a/fs/ceph/ceph_fs.h b/fs/ceph/ceph_fs.h
new file mode 100644 (file)
index 0000000..0c2241e
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * ceph_fs.h - Ceph constants and data types to share between kernel and
+ * user space.
+ *
+ * Most types in this file are defined as little-endian, and are
+ * primarily intended to describe data structures that pass over the
+ * wire or that are stored on disk.
+ *
+ * LGPL2
+ */
+
+#ifndef _FS_CEPH_CEPH_FS_H
+#define _FS_CEPH_CEPH_FS_H
+
+#include "msgr.h"
+#include "rados.h"
+
+/*
+ * Ceph release version
+ */
+#define CEPH_VERSION_MAJOR 0
+#define CEPH_VERSION_MINOR 19
+#define CEPH_VERSION_PATCH 0
+
+#define _CEPH_STRINGIFY(x) #x
+#define CEPH_STRINGIFY(x) _CEPH_STRINGIFY(x)
+#define CEPH_MAKE_VERSION(x, y, z) CEPH_STRINGIFY(x) "." CEPH_STRINGIFY(y) \
+       "." CEPH_STRINGIFY(z)
+#define CEPH_VERSION CEPH_MAKE_VERSION(CEPH_VERSION_MAJOR, \
+                                      CEPH_VERSION_MINOR, CEPH_VERSION_PATCH)
+
+/*
+ * subprotocol versions.  when specific messages types or high-level
+ * protocols change, bump the affected components.  we keep rev
+ * internal cluster protocols separately from the public,
+ * client-facing protocol.
+ */
+#define CEPH_OSD_PROTOCOL     8 /* cluster internal */
+#define CEPH_MDS_PROTOCOL     9 /* cluster internal */
+#define CEPH_MON_PROTOCOL     5 /* cluster internal */
+#define CEPH_OSDC_PROTOCOL   24 /* server/client */
+#define CEPH_MDSC_PROTOCOL   32 /* server/client */
+#define CEPH_MONC_PROTOCOL   15 /* server/client */
+
+
+#define CEPH_INO_ROOT  1
+#define CEPH_INO_CEPH  2        /* hidden .ceph dir */
+
+/* arbitrary limit on max # of monitors (cluster of 3 is typical) */
+#define CEPH_MAX_MON   31
+
+
+/*
+ * feature bits
+ */
+#define CEPH_FEATURE_SUPPORTED  0
+#define CEPH_FEATURE_REQUIRED   0
+
+
+/*
+ * ceph_file_layout - describe data layout for a file/inode
+ */
+struct ceph_file_layout {
+       /* file -> object mapping */
+       __le32 fl_stripe_unit;     /* stripe unit, in bytes.  must be multiple
+                                     of page size. */
+       __le32 fl_stripe_count;    /* over this many objects */
+       __le32 fl_object_size;     /* until objects are this big, then move to
+                                     new objects */
+       __le32 fl_cas_hash;        /* 0 = none; 1 = sha256 */
+
+       /* pg -> disk layout */
+       __le32 fl_object_stripe_unit;  /* for per-object parity, if any */
+
+       /* object -> pg layout */
+       __le32 fl_pg_preferred; /* preferred primary for pg (-1 for none) */
+       __le32 fl_pg_pool;      /* namespace, crush ruleset, rep level */
+} __attribute__ ((packed));
+
+#define CEPH_MIN_STRIPE_UNIT 65536
+
+int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
+
+
+/* crypto algorithms */
+#define CEPH_CRYPTO_NONE 0x0
+#define CEPH_CRYPTO_AES  0x1
+
+/* security/authentication protocols */
+#define CEPH_AUTH_UNKNOWN      0x0
+#define CEPH_AUTH_NONE         0x1
+#define CEPH_AUTH_CEPHX                0x2
+
+
+/*********************************************
+ * message layer
+ */
+
+/*
+ * message types
+ */
+
+/* misc */
+#define CEPH_MSG_SHUTDOWN               1
+#define CEPH_MSG_PING                   2
+
+/* client <-> monitor */
+#define CEPH_MSG_MON_MAP                4
+#define CEPH_MSG_MON_GET_MAP            5
+#define CEPH_MSG_STATFS                 13
+#define CEPH_MSG_STATFS_REPLY           14
+#define CEPH_MSG_MON_SUBSCRIBE          15
+#define CEPH_MSG_MON_SUBSCRIBE_ACK      16
+#define CEPH_MSG_AUTH                  17
+#define CEPH_MSG_AUTH_REPLY            18
+
+/* client <-> mds */
+#define CEPH_MSG_MDS_MAP                21
+
+#define CEPH_MSG_CLIENT_SESSION         22
+#define CEPH_MSG_CLIENT_RECONNECT       23
+
+#define CEPH_MSG_CLIENT_REQUEST         24
+#define CEPH_MSG_CLIENT_REQUEST_FORWARD 25
+#define CEPH_MSG_CLIENT_REPLY           26
+#define CEPH_MSG_CLIENT_CAPS            0x310
+#define CEPH_MSG_CLIENT_LEASE           0x311
+#define CEPH_MSG_CLIENT_SNAP            0x312
+#define CEPH_MSG_CLIENT_CAPRELEASE      0x313
+
+/* osd */
+#define CEPH_MSG_OSD_MAP          41
+#define CEPH_MSG_OSD_OP           42
+#define CEPH_MSG_OSD_OPREPLY      43
+
+struct ceph_mon_request_header {
+       __le64 have_version;
+       __le16 session_mon;
+       __le64 session_mon_tid;
+} __attribute__ ((packed));
+
+struct ceph_mon_statfs {
+       struct ceph_mon_request_header monhdr;
+       struct ceph_fsid fsid;
+} __attribute__ ((packed));
+
+struct ceph_statfs {
+       __le64 kb, kb_used, kb_avail;
+       __le64 num_objects;
+} __attribute__ ((packed));
+
+struct ceph_mon_statfs_reply {
+       struct ceph_fsid fsid;
+       __le64 version;
+       struct ceph_statfs st;
+} __attribute__ ((packed));
+
+struct ceph_osd_getmap {
+       struct ceph_mon_request_header monhdr;
+       struct ceph_fsid fsid;
+       __le32 start;
+} __attribute__ ((packed));
+
+struct ceph_mds_getmap {
+       struct ceph_mon_request_header monhdr;
+       struct ceph_fsid fsid;
+} __attribute__ ((packed));
+
+struct ceph_client_mount {
+       struct ceph_mon_request_header monhdr;
+} __attribute__ ((packed));
+
+struct ceph_mon_subscribe_item {
+       __le64 have_version;    __le64 have;
+       __u8 onetime;
+} __attribute__ ((packed));
+
+struct ceph_mon_subscribe_ack {
+       __le32 duration;         /* seconds */
+       struct ceph_fsid fsid;
+} __attribute__ ((packed));
+
+/*
+ * mds states
+ *   > 0 -> in
+ *  <= 0 -> out
+ */
+#define CEPH_MDS_STATE_DNE          0  /* down, does not exist. */
+#define CEPH_MDS_STATE_STOPPED     -1  /* down, once existed, but no subtrees.
+                                         empty log. */
+#define CEPH_MDS_STATE_BOOT        -4  /* up, boot announcement. */
+#define CEPH_MDS_STATE_STANDBY     -5  /* up, idle.  waiting for assignment. */
+#define CEPH_MDS_STATE_CREATING    -6  /* up, creating MDS instance. */
+#define CEPH_MDS_STATE_STARTING    -7  /* up, starting previously stopped mds */
+#define CEPH_MDS_STATE_STANDBY_REPLAY -8 /* up, tailing active node's journal */
+
+#define CEPH_MDS_STATE_REPLAY       8  /* up, replaying journal. */
+#define CEPH_MDS_STATE_RESOLVE      9  /* up, disambiguating distributed
+                                         operations (import, rename, etc.) */
+#define CEPH_MDS_STATE_RECONNECT    10 /* up, reconnect to clients */
+#define CEPH_MDS_STATE_REJOIN       11 /* up, rejoining distributed cache */
+#define CEPH_MDS_STATE_CLIENTREPLAY 12 /* up, replaying client operations */
+#define CEPH_MDS_STATE_ACTIVE       13 /* up, active */
+#define CEPH_MDS_STATE_STOPPING     14 /* up, but exporting metadata */
+
+extern const char *ceph_mds_state_name(int s);
+
+
+/*
+ * metadata lock types.
+ *  - these are bitmasks.. we can compose them
+ *  - they also define the lock ordering by the MDS
+ *  - a few of these are internal to the mds
+ */
+#define CEPH_LOCK_DN          1
+#define CEPH_LOCK_ISNAP       2
+#define CEPH_LOCK_IVERSION    4     /* mds internal */
+#define CEPH_LOCK_IFILE       8     /* mds internal */
+#define CEPH_LOCK_IAUTH       32
+#define CEPH_LOCK_ILINK       64
+#define CEPH_LOCK_IDFT        128   /* dir frag tree */
+#define CEPH_LOCK_INEST       256   /* mds internal */
+#define CEPH_LOCK_IXATTR      512
+#define CEPH_LOCK_INO         2048  /* immutable inode bits; not a lock */
+
+/* client_session ops */
+enum {
+       CEPH_SESSION_REQUEST_OPEN,
+       CEPH_SESSION_OPEN,
+       CEPH_SESSION_REQUEST_CLOSE,
+       CEPH_SESSION_CLOSE,
+       CEPH_SESSION_REQUEST_RENEWCAPS,
+       CEPH_SESSION_RENEWCAPS,
+       CEPH_SESSION_STALE,
+       CEPH_SESSION_RECALL_STATE,
+};
+
+extern const char *ceph_session_op_name(int op);
+
+struct ceph_mds_session_head {
+       __le32 op;
+       __le64 seq;
+       struct ceph_timespec stamp;
+       __le32 max_caps, max_leases;
+} __attribute__ ((packed));
+
+/* client_request */
+/*
+ * metadata ops.
+ *  & 0x001000 -> write op
+ *  & 0x010000 -> follow symlink (e.g. stat(), not lstat()).
+ &  & 0x100000 -> use weird ino/path trace
+ */
+#define CEPH_MDS_OP_WRITE        0x001000
+enum {
+       CEPH_MDS_OP_LOOKUP     = 0x00100,
+       CEPH_MDS_OP_GETATTR    = 0x00101,
+       CEPH_MDS_OP_LOOKUPHASH = 0x00102,
+       CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
+
+       CEPH_MDS_OP_SETXATTR   = 0x01105,
+       CEPH_MDS_OP_RMXATTR    = 0x01106,
+       CEPH_MDS_OP_SETLAYOUT  = 0x01107,
+       CEPH_MDS_OP_SETATTR    = 0x01108,
+
+       CEPH_MDS_OP_MKNOD      = 0x01201,
+       CEPH_MDS_OP_LINK       = 0x01202,
+       CEPH_MDS_OP_UNLINK     = 0x01203,
+       CEPH_MDS_OP_RENAME     = 0x01204,
+       CEPH_MDS_OP_MKDIR      = 0x01220,
+       CEPH_MDS_OP_RMDIR      = 0x01221,
+       CEPH_MDS_OP_SYMLINK    = 0x01222,
+
+       CEPH_MDS_OP_CREATE     = 0x01301,
+       CEPH_MDS_OP_OPEN       = 0x00302,
+       CEPH_MDS_OP_READDIR    = 0x00305,
+
+       CEPH_MDS_OP_LOOKUPSNAP = 0x00400,
+       CEPH_MDS_OP_MKSNAP     = 0x01400,
+       CEPH_MDS_OP_RMSNAP     = 0x01401,
+       CEPH_MDS_OP_LSSNAP     = 0x00402,
+};
+
+extern const char *ceph_mds_op_name(int op);
+
+
+#define CEPH_SETATTR_MODE   1
+#define CEPH_SETATTR_UID    2
+#define CEPH_SETATTR_GID    4
+#define CEPH_SETATTR_MTIME  8
+#define CEPH_SETATTR_ATIME 16
+#define CEPH_SETATTR_SIZE  32
+#define CEPH_SETATTR_CTIME 64
+
+union ceph_mds_request_args {
+       struct {
+               __le32 mask;                 /* CEPH_CAP_* */
+       } __attribute__ ((packed)) getattr;
+       struct {
+               __le32 mode;
+               __le32 uid;
+               __le32 gid;
+               struct ceph_timespec mtime;
+               struct ceph_timespec atime;
+               __le64 size, old_size;       /* old_size needed by truncate */
+               __le32 mask;                 /* CEPH_SETATTR_* */
+       } __attribute__ ((packed)) setattr;
+       struct {
+               __le32 frag;                 /* which dir fragment */
+               __le32 max_entries;          /* how many dentries to grab */
+       } __attribute__ ((packed)) readdir;
+       struct {
+               __le32 mode;
+               __le32 rdev;
+       } __attribute__ ((packed)) mknod;
+       struct {
+               __le32 mode;
+       } __attribute__ ((packed)) mkdir;
+       struct {
+               __le32 flags;
+               __le32 mode;
+               __le32 stripe_unit;          /* layout for newly created file */
+               __le32 stripe_count;         /* ... */
+               __le32 object_size;
+               __le32 file_replication;
+               __le32 preferred;
+       } __attribute__ ((packed)) open;
+       struct {
+               __le32 flags;
+       } __attribute__ ((packed)) setxattr;
+       struct {
+               struct ceph_file_layout layout;
+       } __attribute__ ((packed)) setlayout;
+} __attribute__ ((packed));
+
+#define CEPH_MDS_FLAG_REPLAY        1  /* this is a replayed op */
+#define CEPH_MDS_FLAG_WANT_DENTRY   2  /* want dentry in reply */
+
+struct ceph_mds_request_head {
+       __le64 oldest_client_tid;
+       __le32 mdsmap_epoch;           /* on client */
+       __le32 flags;                  /* CEPH_MDS_FLAG_* */
+       __u8 num_retry, num_fwd;       /* count retry, fwd attempts */
+       __le16 num_releases;           /* # include cap/lease release records */
+       __le32 op;                     /* mds op code */
+       __le32 caller_uid, caller_gid;
+       __le64 ino;                    /* use this ino for openc, mkdir, mknod,
+                                         etc. (if replaying) */
+       union ceph_mds_request_args args;
+} __attribute__ ((packed));
+
+/* cap/lease release record */
+struct ceph_mds_request_release {
+       __le64 ino, cap_id;            /* ino and unique cap id */
+       __le32 caps, wanted;           /* new issued, wanted */
+       __le32 seq, issue_seq, mseq;
+       __le32 dname_seq;              /* if releasing a dentry lease, a */
+       __le32 dname_len;              /* string follows. */
+} __attribute__ ((packed));
+
+/* client reply */
+struct ceph_mds_reply_head {
+       __le32 op;
+       __le32 result;
+       __le32 mdsmap_epoch;
+       __u8 safe;                     /* true if committed to disk */
+       __u8 is_dentry, is_target;     /* true if dentry, target inode records
+                                         are included with reply */
+} __attribute__ ((packed));
+
+/* one for each node split */
+struct ceph_frag_tree_split {
+       __le32 frag;                   /* this frag splits... */
+       __le32 by;                     /* ...by this many bits */
+} __attribute__ ((packed));
+
+struct ceph_frag_tree_head {
+       __le32 nsplits;                /* num ceph_frag_tree_split records */
+       struct ceph_frag_tree_split splits[];
+} __attribute__ ((packed));
+
+/* capability issue, for bundling with mds reply */
+struct ceph_mds_reply_cap {
+       __le32 caps, wanted;           /* caps issued, wanted */
+       __le64 cap_id;
+       __le32 seq, mseq;
+       __le64 realm;                  /* snap realm */
+       __u8 flags;                    /* CEPH_CAP_FLAG_* */
+} __attribute__ ((packed));
+
+#define CEPH_CAP_FLAG_AUTH  1          /* cap is issued by auth mds */
+
+/* inode record, for bundling with mds reply */
+struct ceph_mds_reply_inode {
+       __le64 ino;
+       __le64 snapid;
+       __le32 rdev;
+       __le64 version;                /* inode version */
+       __le64 xattr_version;          /* version for xattr blob */
+       struct ceph_mds_reply_cap cap; /* caps issued for this inode */
+       struct ceph_file_layout layout;
+       struct ceph_timespec ctime, mtime, atime;
+       __le32 time_warp_seq;
+       __le64 size, max_size, truncate_size;
+       __le32 truncate_seq;
+       __le32 mode, uid, gid;
+       __le32 nlink;
+       __le64 files, subdirs, rbytes, rfiles, rsubdirs;  /* dir stats */
+       struct ceph_timespec rctime;
+       struct ceph_frag_tree_head fragtree;  /* (must be at end of struct) */
+} __attribute__ ((packed));
+/* followed by frag array, then symlink string, then xattr blob */
+
+/* reply_lease follows dname, and reply_inode */
+struct ceph_mds_reply_lease {
+       __le16 mask;            /* lease type(s) */
+       __le32 duration_ms;     /* lease duration */
+       __le32 seq;
+} __attribute__ ((packed));
+
+struct ceph_mds_reply_dirfrag {
+       __le32 frag;            /* fragment */
+       __le32 auth;            /* auth mds, if this is a delegation point */
+       __le32 ndist;           /* number of mds' this is replicated on */
+       __le32 dist[];
+} __attribute__ ((packed));
+
+/* file access modes */
+#define CEPH_FILE_MODE_PIN        0
+#define CEPH_FILE_MODE_RD         1
+#define CEPH_FILE_MODE_WR         2
+#define CEPH_FILE_MODE_RDWR       3  /* RD | WR */
+#define CEPH_FILE_MODE_LAZY       4  /* lazy io */
+#define CEPH_FILE_MODE_NUM        8  /* bc these are bit fields.. mostly */
+
+int ceph_flags_to_mode(int flags);
+
+
+/* capability bits */
+#define CEPH_CAP_PIN         1  /* no specific capabilities beyond the pin */
+
+/* generic cap bits */
+#define CEPH_CAP_GSHARED     1  /* client can reads */
+#define CEPH_CAP_GEXCL       2  /* client can read and update */
+#define CEPH_CAP_GCACHE      4  /* (file) client can cache reads */
+#define CEPH_CAP_GRD         8  /* (file) client can read */
+#define CEPH_CAP_GWR        16  /* (file) client can write */
+#define CEPH_CAP_GBUFFER    32  /* (file) client can buffer writes */
+#define CEPH_CAP_GWREXTEND  64  /* (file) client can extend EOF */
+#define CEPH_CAP_GLAZYIO   128  /* (file) client can perform lazy io */
+
+/* per-lock shift */
+#define CEPH_CAP_SAUTH      2
+#define CEPH_CAP_SLINK      4
+#define CEPH_CAP_SXATTR     6
+#define CEPH_CAP_SFILE      8   /* goes at the end (uses >2 cap bits) */
+
+#define CEPH_CAP_BITS       16
+
+/* composed values */
+#define CEPH_CAP_AUTH_SHARED  (CEPH_CAP_GSHARED  << CEPH_CAP_SAUTH)
+#define CEPH_CAP_AUTH_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SAUTH)
+#define CEPH_CAP_LINK_SHARED  (CEPH_CAP_GSHARED  << CEPH_CAP_SLINK)
+#define CEPH_CAP_LINK_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SLINK)
+#define CEPH_CAP_XATTR_SHARED (CEPH_CAP_GSHARED  << CEPH_CAP_SXATTR)
+#define CEPH_CAP_XATTR_EXCL    (CEPH_CAP_GEXCL     << CEPH_CAP_SXATTR)
+#define CEPH_CAP_FILE(x)    (x << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_SHARED   (CEPH_CAP_GSHARED   << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_CACHE    (CEPH_CAP_GCACHE    << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_RD       (CEPH_CAP_GRD       << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_WR       (CEPH_CAP_GWR       << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_BUFFER   (CEPH_CAP_GBUFFER   << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_LAZYIO   (CEPH_CAP_GLAZYIO   << CEPH_CAP_SFILE)
+
+/* cap masks (for getattr) */
+#define CEPH_STAT_CAP_INODE    CEPH_CAP_PIN
+#define CEPH_STAT_CAP_TYPE     CEPH_CAP_PIN  /* mode >> 12 */
+#define CEPH_STAT_CAP_SYMLINK  CEPH_CAP_PIN
+#define CEPH_STAT_CAP_UID      CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_GID      CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_MODE     CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_NLINK    CEPH_CAP_LINK_SHARED
+#define CEPH_STAT_CAP_LAYOUT   CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_MTIME    CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_SIZE     CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_ATIME    CEPH_CAP_FILE_SHARED  /* fixme */
+#define CEPH_STAT_CAP_XATTR    CEPH_CAP_XATTR_SHARED
+#define CEPH_STAT_CAP_INODE_ALL (CEPH_CAP_PIN |                        \
+                                CEPH_CAP_AUTH_SHARED | \
+                                CEPH_CAP_LINK_SHARED | \
+                                CEPH_CAP_FILE_SHARED | \
+                                CEPH_CAP_XATTR_SHARED)
+
+#define CEPH_CAP_ANY_SHARED (CEPH_CAP_AUTH_SHARED |                    \
+                             CEPH_CAP_LINK_SHARED |                    \
+                             CEPH_CAP_XATTR_SHARED |                   \
+                             CEPH_CAP_FILE_SHARED)
+#define CEPH_CAP_ANY_RD   (CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_RD |    \
+                          CEPH_CAP_FILE_CACHE)
+
+#define CEPH_CAP_ANY_EXCL (CEPH_CAP_AUTH_EXCL |                \
+                          CEPH_CAP_LINK_EXCL |         \
+                          CEPH_CAP_XATTR_EXCL |        \
+                          CEPH_CAP_FILE_EXCL)
+#define CEPH_CAP_ANY_FILE_WR (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |        \
+                             CEPH_CAP_FILE_EXCL)
+#define CEPH_CAP_ANY_WR   (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR)
+#define CEPH_CAP_ANY      (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \
+                          CEPH_CAP_ANY_FILE_WR | CEPH_CAP_PIN)
+
+#define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \
+                       CEPH_LOCK_IXATTR)
+
+int ceph_caps_for_mode(int mode);
+
+enum {
+       CEPH_CAP_OP_GRANT,         /* mds->client grant */
+       CEPH_CAP_OP_REVOKE,        /* mds->client revoke */
+       CEPH_CAP_OP_TRUNC,         /* mds->client trunc notify */
+       CEPH_CAP_OP_EXPORT,        /* mds has exported the cap */
+       CEPH_CAP_OP_IMPORT,        /* mds has imported the cap */
+       CEPH_CAP_OP_UPDATE,        /* client->mds update */
+       CEPH_CAP_OP_DROP,          /* client->mds drop cap bits */
+       CEPH_CAP_OP_FLUSH,         /* client->mds cap writeback */
+       CEPH_CAP_OP_FLUSH_ACK,     /* mds->client flushed */
+       CEPH_CAP_OP_FLUSHSNAP,     /* client->mds flush snapped metadata */
+       CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */
+       CEPH_CAP_OP_RELEASE,       /* client->mds release (clean) cap */
+       CEPH_CAP_OP_RENEW,         /* client->mds renewal request */
+};
+
+extern const char *ceph_cap_op_name(int op);
+
+/*
+ * caps message, used for capability callbacks, acks, requests, etc.
+ */
+struct ceph_mds_caps {
+       __le32 op;                  /* CEPH_CAP_OP_* */
+       __le64 ino, realm;
+       __le64 cap_id;
+       __le32 seq, issue_seq;
+       __le32 caps, wanted, dirty; /* latest issued/wanted/dirty */
+       __le32 migrate_seq;
+       __le64 snap_follows;
+       __le32 snap_trace_len;
+
+       /* authlock */
+       __le32 uid, gid, mode;
+
+       /* linklock */
+       __le32 nlink;
+
+       /* xattrlock */
+       __le32 xattr_len;
+       __le64 xattr_version;
+
+       /* filelock */
+       __le64 size, max_size, truncate_size;
+       __le32 truncate_seq;
+       struct ceph_timespec mtime, atime, ctime;
+       struct ceph_file_layout layout;
+       __le32 time_warp_seq;
+} __attribute__ ((packed));
+
+/* cap release msg head */
+struct ceph_mds_cap_release {
+       __le32 num;                /* number of cap_items that follow */
+} __attribute__ ((packed));
+
+struct ceph_mds_cap_item {
+       __le64 ino;
+       __le64 cap_id;
+       __le32 migrate_seq, seq;
+} __attribute__ ((packed));
+
+#define CEPH_MDS_LEASE_REVOKE           1  /*    mds  -> client */
+#define CEPH_MDS_LEASE_RELEASE          2  /* client  -> mds    */
+#define CEPH_MDS_LEASE_RENEW            3  /* client <-> mds    */
+#define CEPH_MDS_LEASE_REVOKE_ACK       4  /* client  -> mds    */
+
+extern const char *ceph_lease_op_name(int o);
+
+/* lease msg header */
+struct ceph_mds_lease {
+       __u8 action;            /* CEPH_MDS_LEASE_* */
+       __le16 mask;            /* which lease */
+       __le64 ino;
+       __le64 first, last;     /* snap range */
+       __le32 seq;
+       __le32 duration_ms;     /* duration of renewal */
+} __attribute__ ((packed));
+/* followed by a __le32+string for dname */
+
+/* client reconnect */
+struct ceph_mds_cap_reconnect {
+       __le64 cap_id;
+       __le32 wanted;
+       __le32 issued;
+       __le64 size;
+       struct ceph_timespec mtime, atime;
+       __le64 snaprealm;
+       __le64 pathbase;        /* base ino for our path to this ino */
+} __attribute__ ((packed));
+/* followed by encoded string */
+
+struct ceph_mds_snaprealm_reconnect {
+       __le64 ino;     /* snap realm base */
+       __le64 seq;     /* snap seq for this snap realm */
+       __le64 parent;  /* parent realm */
+} __attribute__ ((packed));
+
+/*
+ * snaps
+ */
+enum {
+       CEPH_SNAP_OP_UPDATE,  /* CREATE or DESTROY */
+       CEPH_SNAP_OP_CREATE,
+       CEPH_SNAP_OP_DESTROY,
+       CEPH_SNAP_OP_SPLIT,
+};
+
+extern const char *ceph_snap_op_name(int o);
+
+/* snap msg header */
+struct ceph_mds_snap_head {
+       __le32 op;                /* CEPH_SNAP_OP_* */
+       __le64 split;             /* ino to split off, if any */
+       __le32 num_split_inos;    /* # inos belonging to new child realm */
+       __le32 num_split_realms;  /* # child realms udner new child realm */
+       __le32 trace_len;         /* size of snap trace blob */
+} __attribute__ ((packed));
+/* followed by split ino list, then split realms, then the trace blob */
+
+/*
+ * encode info about a snaprealm, as viewed by a client
+ */
+struct ceph_mds_snap_realm {
+       __le64 ino;           /* ino */
+       __le64 created;       /* snap: when created */
+       __le64 parent;        /* ino: parent realm */
+       __le64 parent_since;  /* snap: same parent since */
+       __le64 seq;           /* snap: version */
+       __le32 num_snaps;
+       __le32 num_prior_parent_snaps;
+} __attribute__ ((packed));
+/* followed by my snap list, then prior parent snap list */
+
+#endif
diff --git a/fs/ceph/ceph_hash.c b/fs/ceph/ceph_hash.c
new file mode 100644 (file)
index 0000000..bd57001
--- /dev/null
@@ -0,0 +1,118 @@
+
+#include "types.h"
+
+/*
+ * Robert Jenkin's hash function.
+ * http://burtleburtle.net/bob/hash/evahash.html
+ * This is in the public domain.
+ */
+#define mix(a, b, c)                                           \
+       do {                                                    \
+               a = a - b;  a = a - c;  a = a ^ (c >> 13);      \
+               b = b - c;  b = b - a;  b = b ^ (a << 8);       \
+               c = c - a;  c = c - b;  c = c ^ (b >> 13);      \
+               a = a - b;  a = a - c;  a = a ^ (c >> 12);      \
+               b = b - c;  b = b - a;  b = b ^ (a << 16);      \
+               c = c - a;  c = c - b;  c = c ^ (b >> 5);       \
+               a = a - b;  a = a - c;  a = a ^ (c >> 3);       \
+               b = b - c;  b = b - a;  b = b ^ (a << 10);      \
+               c = c - a;  c = c - b;  c = c ^ (b >> 15);      \
+       } while (0)
+
+unsigned ceph_str_hash_rjenkins(const char *str, unsigned length)
+{
+       const unsigned char *k = (const unsigned char *)str;
+       __u32 a, b, c;  /* the internal state */
+       __u32 len;      /* how many key bytes still need mixing */
+
+       /* Set up the internal state */
+       len = length;
+       a = 0x9e3779b9;      /* the golden ratio; an arbitrary value */
+       b = a;
+       c = 0;               /* variable initialization of internal state */
+
+       /* handle most of the key */
+       while (len >= 12) {
+               a = a + (k[0] + ((__u32)k[1] << 8) + ((__u32)k[2] << 16) +
+                        ((__u32)k[3] << 24));
+               b = b + (k[4] + ((__u32)k[5] << 8) + ((__u32)k[6] << 16) +
+                        ((__u32)k[7] << 24));
+               c = c + (k[8] + ((__u32)k[9] << 8) + ((__u32)k[10] << 16) +
+                        ((__u32)k[11] << 24));
+               mix(a, b, c);
+               k = k + 12;
+               len = len - 12;
+       }
+
+       /* handle the last 11 bytes */
+       c = c + length;
+       switch (len) {            /* all the case statements fall through */
+       case 11:
+               c = c + ((__u32)k[10] << 24);
+       case 10:
+               c = c + ((__u32)k[9] << 16);
+       case 9:
+               c = c + ((__u32)k[8] << 8);
+               /* the first byte of c is reserved for the length */
+       case 8:
+               b = b + ((__u32)k[7] << 24);
+       case 7:
+               b = b + ((__u32)k[6] << 16);
+       case 6:
+               b = b + ((__u32)k[5] << 8);
+       case 5:
+               b = b + k[4];
+       case 4:
+               a = a + ((__u32)k[3] << 24);
+       case 3:
+               a = a + ((__u32)k[2] << 16);
+       case 2:
+               a = a + ((__u32)k[1] << 8);
+       case 1:
+               a = a + k[0];
+               /* case 0: nothing left to add */
+       }
+       mix(a, b, c);
+
+       return c;
+}
+
+/*
+ * linux dcache hash
+ */
+unsigned ceph_str_hash_linux(const char *str, unsigned length)
+{
+       unsigned long hash = 0;
+       unsigned char c;
+
+       while (length--) {
+               c = *str++;
+               hash = (hash + (c << 4) + (c >> 4)) * 11;
+       }
+       return hash;
+}
+
+
+unsigned ceph_str_hash(int type, const char *s, unsigned len)
+{
+       switch (type) {
+       case CEPH_STR_HASH_LINUX:
+               return ceph_str_hash_linux(s, len);
+       case CEPH_STR_HASH_RJENKINS:
+               return ceph_str_hash_rjenkins(s, len);
+       default:
+               return -1;
+       }
+}
+
+const char *ceph_str_hash_name(int type)
+{
+       switch (type) {
+       case CEPH_STR_HASH_LINUX:
+               return "linux";
+       case CEPH_STR_HASH_RJENKINS:
+               return "rjenkins";
+       default:
+               return "unknown";
+       }
+}
diff --git a/fs/ceph/ceph_hash.h b/fs/ceph/ceph_hash.h
new file mode 100644 (file)
index 0000000..5ac470c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _FS_CEPH_HASH_H
+#define _FS_CEPH_HASH_H
+
+#define CEPH_STR_HASH_LINUX      0x1  /* linux dcache hash */
+#define CEPH_STR_HASH_RJENKINS   0x2  /* robert jenkins' */
+
+extern unsigned ceph_str_hash_linux(const char *s, unsigned len);
+extern unsigned ceph_str_hash_rjenkins(const char *s, unsigned len);
+
+extern unsigned ceph_str_hash(int type, const char *s, unsigned len);
+extern const char *ceph_str_hash_name(int type);
+
+#endif
diff --git a/fs/ceph/ceph_strings.c b/fs/ceph/ceph_strings.c
new file mode 100644 (file)
index 0000000..8e4be6a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Ceph string constants
+ */
+#include "types.h"
+
+const char *ceph_entity_type_name(int type)
+{
+       switch (type) {
+       case CEPH_ENTITY_TYPE_MDS: return "mds";
+       case CEPH_ENTITY_TYPE_OSD: return "osd";
+       case CEPH_ENTITY_TYPE_MON: return "mon";
+       case CEPH_ENTITY_TYPE_CLIENT: return "client";
+       case CEPH_ENTITY_TYPE_ADMIN: return "admin";
+       case CEPH_ENTITY_TYPE_AUTH: return "auth";
+       default: return "unknown";
+       }
+}
+
+const char *ceph_osd_op_name(int op)
+{
+       switch (op) {
+       case CEPH_OSD_OP_READ: return "read";
+       case CEPH_OSD_OP_STAT: return "stat";
+
+       case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
+
+       case CEPH_OSD_OP_WRITE: return "write";
+       case CEPH_OSD_OP_DELETE: return "delete";
+       case CEPH_OSD_OP_TRUNCATE: return "truncate";
+       case CEPH_OSD_OP_ZERO: return "zero";
+       case CEPH_OSD_OP_WRITEFULL: return "writefull";
+
+       case CEPH_OSD_OP_APPEND: return "append";
+       case CEPH_OSD_OP_STARTSYNC: return "startsync";
+       case CEPH_OSD_OP_SETTRUNC: return "settrunc";
+       case CEPH_OSD_OP_TRIMTRUNC: return "trimtrunc";
+
+       case CEPH_OSD_OP_TMAPUP: return "tmapup";
+       case CEPH_OSD_OP_TMAPGET: return "tmapget";
+       case CEPH_OSD_OP_TMAPPUT: return "tmapput";
+
+       case CEPH_OSD_OP_GETXATTR: return "getxattr";
+       case CEPH_OSD_OP_GETXATTRS: return "getxattrs";
+       case CEPH_OSD_OP_SETXATTR: return "setxattr";
+       case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
+       case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
+       case CEPH_OSD_OP_RMXATTR: return "rmxattr";
+
+       case CEPH_OSD_OP_PULL: return "pull";
+       case CEPH_OSD_OP_PUSH: return "push";
+       case CEPH_OSD_OP_BALANCEREADS: return "balance-reads";
+       case CEPH_OSD_OP_UNBALANCEREADS: return "unbalance-reads";
+       case CEPH_OSD_OP_SCRUB: return "scrub";
+
+       case CEPH_OSD_OP_WRLOCK: return "wrlock";
+       case CEPH_OSD_OP_WRUNLOCK: return "wrunlock";
+       case CEPH_OSD_OP_RDLOCK: return "rdlock";
+       case CEPH_OSD_OP_RDUNLOCK: return "rdunlock";
+       case CEPH_OSD_OP_UPLOCK: return "uplock";
+       case CEPH_OSD_OP_DNLOCK: return "dnlock";
+
+       case CEPH_OSD_OP_CALL: return "call";
+
+       case CEPH_OSD_OP_PGLS: return "pgls";
+       }
+       return "???";
+}
+
+const char *ceph_mds_state_name(int s)
+{
+       switch (s) {
+               /* down and out */
+       case CEPH_MDS_STATE_DNE:        return "down:dne";
+       case CEPH_MDS_STATE_STOPPED:    return "down:stopped";
+               /* up and out */
+       case CEPH_MDS_STATE_BOOT:       return "up:boot";
+       case CEPH_MDS_STATE_STANDBY:    return "up:standby";
+       case CEPH_MDS_STATE_STANDBY_REPLAY:    return "up:standby-replay";
+       case CEPH_MDS_STATE_CREATING:   return "up:creating";
+       case CEPH_MDS_STATE_STARTING:   return "up:starting";
+               /* up and in */
+       case CEPH_MDS_STATE_REPLAY:     return "up:replay";
+       case CEPH_MDS_STATE_RESOLVE:    return "up:resolve";
+       case CEPH_MDS_STATE_RECONNECT:  return "up:reconnect";
+       case CEPH_MDS_STATE_REJOIN:     return "up:rejoin";
+       case CEPH_MDS_STATE_CLIENTREPLAY: return "up:clientreplay";
+       case CEPH_MDS_STATE_ACTIVE:     return "up:active";
+       case CEPH_MDS_STATE_STOPPING:   return "up:stopping";
+       }
+       return "???";
+}
+
+const char *ceph_session_op_name(int op)
+{
+       switch (op) {
+       case CEPH_SESSION_REQUEST_OPEN: return "request_open";
+       case CEPH_SESSION_OPEN: return "open";
+       case CEPH_SESSION_REQUEST_CLOSE: return "request_close";
+       case CEPH_SESSION_CLOSE: return "close";
+       case CEPH_SESSION_REQUEST_RENEWCAPS: return "request_renewcaps";
+       case CEPH_SESSION_RENEWCAPS: return "renewcaps";
+       case CEPH_SESSION_STALE: return "stale";
+       case CEPH_SESSION_RECALL_STATE: return "recall_state";
+       }
+       return "???";
+}
+
+const char *ceph_mds_op_name(int op)
+{
+       switch (op) {
+       case CEPH_MDS_OP_LOOKUP:  return "lookup";
+       case CEPH_MDS_OP_LOOKUPHASH:  return "lookuphash";
+       case CEPH_MDS_OP_LOOKUPPARENT:  return "lookupparent";
+       case CEPH_MDS_OP_GETATTR:  return "getattr";
+       case CEPH_MDS_OP_SETXATTR: return "setxattr";
+       case CEPH_MDS_OP_SETATTR: return "setattr";
+       case CEPH_MDS_OP_RMXATTR: return "rmxattr";
+       case CEPH_MDS_OP_READDIR: return "readdir";
+       case CEPH_MDS_OP_MKNOD: return "mknod";
+       case CEPH_MDS_OP_LINK: return "link";
+       case CEPH_MDS_OP_UNLINK: return "unlink";
+       case CEPH_MDS_OP_RENAME: return "rename";
+       case CEPH_MDS_OP_MKDIR: return "mkdir";
+       case CEPH_MDS_OP_RMDIR: return "rmdir";
+       case CEPH_MDS_OP_SYMLINK: return "symlink";
+       case CEPH_MDS_OP_CREATE: return "create";
+       case CEPH_MDS_OP_OPEN: return "open";
+       case CEPH_MDS_OP_LOOKUPSNAP: return "lookupsnap";
+       case CEPH_MDS_OP_LSSNAP: return "lssnap";
+       case CEPH_MDS_OP_MKSNAP: return "mksnap";
+       case CEPH_MDS_OP_RMSNAP: return "rmsnap";
+       }
+       return "???";
+}
+
+const char *ceph_cap_op_name(int op)
+{
+       switch (op) {
+       case CEPH_CAP_OP_GRANT: return "grant";
+       case CEPH_CAP_OP_REVOKE: return "revoke";
+       case CEPH_CAP_OP_TRUNC: return "trunc";
+       case CEPH_CAP_OP_EXPORT: return "export";
+       case CEPH_CAP_OP_IMPORT: return "import";
+       case CEPH_CAP_OP_UPDATE: return "update";
+       case CEPH_CAP_OP_DROP: return "drop";
+       case CEPH_CAP_OP_FLUSH: return "flush";
+       case CEPH_CAP_OP_FLUSH_ACK: return "flush_ack";
+       case CEPH_CAP_OP_FLUSHSNAP: return "flushsnap";
+       case CEPH_CAP_OP_FLUSHSNAP_ACK: return "flushsnap_ack";
+       case CEPH_CAP_OP_RELEASE: return "release";
+       case CEPH_CAP_OP_RENEW: return "renew";
+       }
+       return "???";
+}
+
+const char *ceph_lease_op_name(int o)
+{
+       switch (o) {
+       case CEPH_MDS_LEASE_REVOKE: return "revoke";
+       case CEPH_MDS_LEASE_RELEASE: return "release";
+       case CEPH_MDS_LEASE_RENEW: return "renew";
+       case CEPH_MDS_LEASE_REVOKE_ACK: return "revoke_ack";
+       }
+       return "???";
+}
+
+const char *ceph_snap_op_name(int o)
+{
+       switch (o) {
+       case CEPH_SNAP_OP_UPDATE: return "update";
+       case CEPH_SNAP_OP_CREATE: return "create";
+       case CEPH_SNAP_OP_DESTROY: return "destroy";
+       case CEPH_SNAP_OP_SPLIT: return "split";
+       }
+       return "???";
+}
diff --git a/fs/ceph/crush/crush.c b/fs/ceph/crush/crush.c
new file mode 100644 (file)
index 0000000..fabd302
--- /dev/null
@@ -0,0 +1,151 @@
+
+#ifdef __KERNEL__
+# include <linux/slab.h>
+#else
+# include <stdlib.h>
+# include <assert.h>
+# define kfree(x) do { if (x) free(x); } while (0)
+# define BUG_ON(x) assert(!(x))
+#endif
+
+#include "crush.h"
+
+const char *crush_bucket_alg_name(int alg)
+{
+       switch (alg) {
+       case CRUSH_BUCKET_UNIFORM: return "uniform";
+       case CRUSH_BUCKET_LIST: return "list";
+       case CRUSH_BUCKET_TREE: return "tree";
+       case CRUSH_BUCKET_STRAW: return "straw";
+       default: return "unknown";
+       }
+}
+
+/**
+ * crush_get_bucket_item_weight - Get weight of an item in given bucket
+ * @b: bucket pointer
+ * @p: item index in bucket
+ */
+int crush_get_bucket_item_weight(struct crush_bucket *b, int p)
+{
+       if (p >= b->size)
+               return 0;
+
+       switch (b->alg) {
+       case CRUSH_BUCKET_UNIFORM:
+               return ((struct crush_bucket_uniform *)b)->item_weight;
+       case CRUSH_BUCKET_LIST:
+               return ((struct crush_bucket_list *)b)->item_weights[p];
+       case CRUSH_BUCKET_TREE:
+               if (p & 1)
+                       return ((struct crush_bucket_tree *)b)->node_weights[p];
+               return 0;
+       case CRUSH_BUCKET_STRAW:
+               return ((struct crush_bucket_straw *)b)->item_weights[p];
+       }
+       return 0;
+}
+
+/**
+ * crush_calc_parents - Calculate parent vectors for the given crush map.
+ * @map: crush_map pointer
+ */
+void crush_calc_parents(struct crush_map *map)
+{
+       int i, b, c;
+
+       for (b = 0; b < map->max_buckets; b++) {
+               if (map->buckets[b] == NULL)
+                       continue;
+               for (i = 0; i < map->buckets[b]->size; i++) {
+                       c = map->buckets[b]->items[i];
+                       BUG_ON(c >= map->max_devices ||
+                              c < -map->max_buckets);
+                       if (c >= 0)
+                               map->device_parents[c] = map->buckets[b]->id;
+                       else
+                               map->bucket_parents[-1-c] = map->buckets[b]->id;
+               }
+       }
+}
+
+void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
+{
+       kfree(b->h.perm);
+       kfree(b->h.items);
+       kfree(b);
+}
+
+void crush_destroy_bucket_list(struct crush_bucket_list *b)
+{
+       kfree(b->item_weights);
+       kfree(b->sum_weights);
+       kfree(b->h.perm);
+       kfree(b->h.items);
+       kfree(b);
+}
+
+void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
+{
+       kfree(b->node_weights);
+       kfree(b);
+}
+
+void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
+{
+       kfree(b->straws);
+       kfree(b->item_weights);
+       kfree(b->h.perm);
+       kfree(b->h.items);
+       kfree(b);
+}
+
+void crush_destroy_bucket(struct crush_bucket *b)
+{
+       switch (b->alg) {
+       case CRUSH_BUCKET_UNIFORM:
+               crush_destroy_bucket_uniform((struct crush_bucket_uniform *)b);
+               break;
+       case CRUSH_BUCKET_LIST:
+               crush_destroy_bucket_list((struct crush_bucket_list *)b);
+               break;
+       case CRUSH_BUCKET_TREE:
+               crush_destroy_bucket_tree((struct crush_bucket_tree *)b);
+               break;
+       case CRUSH_BUCKET_STRAW:
+               crush_destroy_bucket_straw((struct crush_bucket_straw *)b);
+               break;
+       }
+}
+
+/**
+ * crush_destroy - Destroy a crush_map
+ * @map: crush_map pointer
+ */
+void crush_destroy(struct crush_map *map)
+{
+       int b;
+
+       /* buckets */
+       if (map->buckets) {
+               for (b = 0; b < map->max_buckets; b++) {
+                       if (map->buckets[b] == NULL)
+                               continue;
+                       crush_destroy_bucket(map->buckets[b]);
+               }
+               kfree(map->buckets);
+       }
+
+       /* rules */
+       if (map->rules) {
+               for (b = 0; b < map->max_rules; b++)
+                       kfree(map->rules[b]);
+               kfree(map->rules);
+       }
+
+       kfree(map->bucket_parents);
+       kfree(map->device_parents);
+       kfree(map);
+}
+
+
diff --git a/fs/ceph/crush/crush.h b/fs/ceph/crush/crush.h
new file mode 100644 (file)
index 0000000..dcd7e75
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef _CRUSH_CRUSH_H
+#define _CRUSH_CRUSH_H
+
+#include <linux/types.h>
+
+/*
+ * CRUSH is a pseudo-random data distribution algorithm that
+ * efficiently distributes input values (typically, data objects)
+ * across a heterogeneous, structured storage cluster.
+ *
+ * The algorithm was originally described in detail in this paper
+ * (although the algorithm has evolved somewhat since then):
+ *
+ *     http://www.ssrc.ucsc.edu/Papers/weil-sc06.pdf
+ *
+ * LGPL2
+ */
+
+
+#define CRUSH_MAGIC 0x00010000ul   /* for detecting algorithm revisions */
+
+
+#define CRUSH_MAX_DEPTH 10  /* max crush hierarchy depth */
+#define CRUSH_MAX_SET   10  /* max size of a mapping result */
+
+
+/*
+ * CRUSH uses user-defined "rules" to describe how inputs should be
+ * mapped to devices.  A rule consists of sequence of steps to perform
+ * to generate the set of output devices.
+ */
+struct crush_rule_step {
+       __u32 op;
+       __s32 arg1;
+       __s32 arg2;
+};
+
+/* step op codes */
+enum {
+       CRUSH_RULE_NOOP = 0,
+       CRUSH_RULE_TAKE = 1,          /* arg1 = value to start with */
+       CRUSH_RULE_CHOOSE_FIRSTN = 2, /* arg1 = num items to pick */
+                                     /* arg2 = type */
+       CRUSH_RULE_CHOOSE_INDEP = 3,  /* same */
+       CRUSH_RULE_EMIT = 4,          /* no args */
+       CRUSH_RULE_CHOOSE_LEAF_FIRSTN = 6,
+       CRUSH_RULE_CHOOSE_LEAF_INDEP = 7,
+};
+
+/*
+ * for specifying choose num (arg1) relative to the max parameter
+ * passed to do_rule
+ */
+#define CRUSH_CHOOSE_N            0
+#define CRUSH_CHOOSE_N_MINUS(x)   (-(x))
+
+/*
+ * The rule mask is used to describe what the rule is intended for.
+ * Given a ruleset and size of output set, we search through the
+ * rule list for a matching rule_mask.
+ */
+struct crush_rule_mask {
+       __u8 ruleset;
+       __u8 type;
+       __u8 min_size;
+       __u8 max_size;
+};
+
+struct crush_rule {
+       __u32 len;
+       struct crush_rule_mask mask;
+       struct crush_rule_step steps[0];
+};
+
+#define crush_rule_size(len) (sizeof(struct crush_rule) + \
+                             (len)*sizeof(struct crush_rule_step))
+
+
+
+/*
+ * A bucket is a named container of other items (either devices or
+ * other buckets).  Items within a bucket are chosen using one of a
+ * few different algorithms.  The table summarizes how the speed of
+ * each option measures up against mapping stability when items are
+ * added or removed.
+ *
+ *  Bucket Alg     Speed       Additions    Removals
+ *  ------------------------------------------------
+ *  uniform         O(1)       poor         poor
+ *  list            O(n)       optimal      poor
+ *  tree            O(log n)   good         good
+ *  straw           O(n)       optimal      optimal
+ */
+enum {
+       CRUSH_BUCKET_UNIFORM = 1,
+       CRUSH_BUCKET_LIST = 2,
+       CRUSH_BUCKET_TREE = 3,
+       CRUSH_BUCKET_STRAW = 4
+};
+extern const char *crush_bucket_alg_name(int alg);
+
+struct crush_bucket {
+       __s32 id;        /* this'll be negative */
+       __u16 type;      /* non-zero; type=0 is reserved for devices */
+       __u8 alg;        /* one of CRUSH_BUCKET_* */
+       __u8 hash;       /* which hash function to use, CRUSH_HASH_* */
+       __u32 weight;    /* 16-bit fixed point */
+       __u32 size;      /* num items */
+       __s32 *items;
+
+       /*
+        * cached random permutation: used for uniform bucket and for
+        * the linear search fallback for the other bucket types.
+        */
+       __u32 perm_x;  /* @x for which *perm is defined */
+       __u32 perm_n;  /* num elements of *perm that are permuted/defined */
+       __u32 *perm;
+};
+
+struct crush_bucket_uniform {
+       struct crush_bucket h;
+       __u32 item_weight;  /* 16-bit fixed point; all items equally weighted */
+};
+
+struct crush_bucket_list {
+       struct crush_bucket h;
+       __u32 *item_weights;  /* 16-bit fixed point */
+       __u32 *sum_weights;   /* 16-bit fixed point.  element i is sum
+                                of weights 0..i, inclusive */
+};
+
+struct crush_bucket_tree {
+       struct crush_bucket h;  /* note: h.size is _tree_ size, not number of
+                                  actual items */
+       __u8 num_nodes;
+       __u32 *node_weights;
+};
+
+struct crush_bucket_straw {
+       struct crush_bucket h;
+       __u32 *item_weights;   /* 16-bit fixed point */
+       __u32 *straws;         /* 16-bit fixed point */
+};
+
+
+
+/*
+ * CRUSH map includes all buckets, rules, etc.
+ */
+struct crush_map {
+       struct crush_bucket **buckets;
+       struct crush_rule **rules;
+
+       /*
+        * Parent pointers to identify the parent bucket a device or
+        * bucket in the hierarchy.  If an item appears more than
+        * once, this is the _last_ time it appeared (where buckets
+        * are processed in bucket id order, from -1 on down to
+        * -max_buckets.
+        */
+       __u32 *bucket_parents;
+       __u32 *device_parents;
+
+       __s32 max_buckets;
+       __u32 max_rules;
+       __s32 max_devices;
+};
+
+
+/* crush.c */
+extern int crush_get_bucket_item_weight(struct crush_bucket *b, int pos);
+extern void crush_calc_parents(struct crush_map *map);
+extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b);
+extern void crush_destroy_bucket_list(struct crush_bucket_list *b);
+extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b);
+extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b);
+extern void crush_destroy_bucket(struct crush_bucket *b);
+extern void crush_destroy(struct crush_map *map);
+
+#endif
diff --git a/fs/ceph/crush/hash.c b/fs/ceph/crush/hash.c
new file mode 100644 (file)
index 0000000..5873aed
--- /dev/null
@@ -0,0 +1,149 @@
+
+#include <linux/types.h>
+#include "hash.h"
+
+/*
+ * Robert Jenkins' function for mixing 32-bit values
+ * http://burtleburtle.net/bob/hash/evahash.html
+ * a, b = random bits, c = input and output
+ */
+#define crush_hashmix(a, b, c) do {                    \
+               a = a-b;  a = a-c;  a = a^(c>>13);      \
+               b = b-c;  b = b-a;  b = b^(a<<8);       \
+               c = c-a;  c = c-b;  c = c^(b>>13);      \
+               a = a-b;  a = a-c;  a = a^(c>>12);      \
+               b = b-c;  b = b-a;  b = b^(a<<16);      \
+               c = c-a;  c = c-b;  c = c^(b>>5);       \
+               a = a-b;  a = a-c;  a = a^(c>>3);       \
+               b = b-c;  b = b-a;  b = b^(a<<10);      \
+               c = c-a;  c = c-b;  c = c^(b>>15);      \
+       } while (0)
+
+#define crush_hash_seed 1315423911
+
+static __u32 crush_hash32_rjenkins1(__u32 a)
+{
+       __u32 hash = crush_hash_seed ^ a;
+       __u32 b = a;
+       __u32 x = 231232;
+       __u32 y = 1232;
+       crush_hashmix(b, x, hash);
+       crush_hashmix(y, a, hash);
+       return hash;
+}
+
+static __u32 crush_hash32_rjenkins1_2(__u32 a, __u32 b)
+{
+       __u32 hash = crush_hash_seed ^ a ^ b;
+       __u32 x = 231232;
+       __u32 y = 1232;
+       crush_hashmix(a, b, hash);
+       crush_hashmix(x, a, hash);
+       crush_hashmix(b, y, hash);
+       return hash;
+}
+
+static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c)
+{
+       __u32 hash = crush_hash_seed ^ a ^ b ^ c;
+       __u32 x = 231232;
+       __u32 y = 1232;
+       crush_hashmix(a, b, hash);
+       crush_hashmix(c, x, hash);
+       crush_hashmix(y, a, hash);
+       crush_hashmix(b, x, hash);
+       crush_hashmix(y, c, hash);
+       return hash;
+}
+
+static __u32 crush_hash32_rjenkins1_4(__u32 a, __u32 b, __u32 c, __u32 d)
+{
+       __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d;
+       __u32 x = 231232;
+       __u32 y = 1232;
+       crush_hashmix(a, b, hash);
+       crush_hashmix(c, d, hash);
+       crush_hashmix(a, x, hash);
+       crush_hashmix(y, b, hash);
+       crush_hashmix(c, x, hash);
+       crush_hashmix(y, d, hash);
+       return hash;
+}
+
+static __u32 crush_hash32_rjenkins1_5(__u32 a, __u32 b, __u32 c, __u32 d,
+                                     __u32 e)
+{
+       __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
+       __u32 x = 231232;
+       __u32 y = 1232;
+       crush_hashmix(a, b, hash);
+       crush_hashmix(c, d, hash);
+       crush_hashmix(e, x, hash);
+       crush_hashmix(y, a, hash);
+       crush_hashmix(b, x, hash);
+       crush_hashmix(y, c, hash);
+       crush_hashmix(d, x, hash);
+       crush_hashmix(y, e, hash);
+       return hash;
+}
+
+
+__u32 crush_hash32(int type, __u32 a)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return crush_hash32_rjenkins1(a);
+       default:
+               return 0;
+       }
+}
+
+__u32 crush_hash32_2(int type, __u32 a, __u32 b)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return crush_hash32_rjenkins1_2(a, b);
+       default:
+               return 0;
+       }
+}
+
+__u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return crush_hash32_rjenkins1_3(a, b, c);
+       default:
+               return 0;
+       }
+}
+
+__u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return crush_hash32_rjenkins1_4(a, b, c, d);
+       default:
+               return 0;
+       }
+}
+
+__u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d, __u32 e)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return crush_hash32_rjenkins1_5(a, b, c, d, e);
+       default:
+               return 0;
+       }
+}
+
+const char *crush_hash_name(int type)
+{
+       switch (type) {
+       case CRUSH_HASH_RJENKINS1:
+               return "rjenkins1";
+       default:
+               return "unknown";
+       }
+}
diff --git a/fs/ceph/crush/hash.h b/fs/ceph/crush/hash.h
new file mode 100644 (file)
index 0000000..ff48e11
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _CRUSH_HASH_H
+#define _CRUSH_HASH_H
+
+#define CRUSH_HASH_RJENKINS1   0
+
+#define CRUSH_HASH_DEFAULT CRUSH_HASH_RJENKINS1
+
+extern const char *crush_hash_name(int type);
+
+extern __u32 crush_hash32(int type, __u32 a);
+extern __u32 crush_hash32_2(int type, __u32 a, __u32 b);
+extern __u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c);
+extern __u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d);
+extern __u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d,
+                           __u32 e);
+
+#endif
diff --git a/fs/ceph/crush/mapper.c b/fs/ceph/crush/mapper.c
new file mode 100644 (file)
index 0000000..9ba54ef
--- /dev/null
@@ -0,0 +1,596 @@
+
+#ifdef __KERNEL__
+# include <linux/string.h>
+# include <linux/slab.h>
+# include <linux/bug.h>
+# include <linux/kernel.h>
+# ifndef dprintk
+#  define dprintk(args...)
+# endif
+#else
+# include <string.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+# define dprintk(args...) /* printf(args) */
+# define kmalloc(x, f) malloc(x)
+# define kfree(x) free(x)
+#endif
+
+#include "crush.h"
+#include "hash.h"
+
+/*
+ * Implement the core CRUSH mapping algorithm.
+ */
+
+/**
+ * crush_find_rule - find a crush_rule id for a given ruleset, type, and size.
+ * @map: the crush_map
+ * @ruleset: the storage ruleset id (user defined)
+ * @type: storage ruleset type (user defined)
+ * @size: output set size
+ */
+int crush_find_rule(struct crush_map *map, int ruleset, int type, int size)
+{
+       int i;
+
+       for (i = 0; i < map->max_rules; i++) {
+               if (map->rules[i] &&
+                   map->rules[i]->mask.ruleset == ruleset &&
+                   map->rules[i]->mask.type == type &&
+                   map->rules[i]->mask.min_size <= size &&
+                   map->rules[i]->mask.max_size >= size)
+                       return i;
+       }
+       return -1;
+}
+
+
+/*
+ * bucket choose methods
+ *
+ * For each bucket algorithm, we have a "choose" method that, given a
+ * crush input @x and replica position (usually, position in output set) @r,
+ * will produce an item in the bucket.
+ */
+
+/*
+ * Choose based on a random permutation of the bucket.
+ *
+ * We used to use some prime number arithmetic to do this, but it
+ * wasn't very random, and had some other bad behaviors.  Instead, we
+ * calculate an actual random permutation of the bucket members.
+ * Since this is expensive, we optimize for the r=0 case, which
+ * captures the vast majority of calls.
+ */
+static int bucket_perm_choose(struct crush_bucket *bucket,
+                             int x, int r)
+{
+       unsigned pr = r % bucket->size;
+       unsigned i, s;
+
+       /* start a new permutation if @x has changed */
+       if (bucket->perm_x != x || bucket->perm_n == 0) {
+               dprintk("bucket %d new x=%d\n", bucket->id, x);
+               bucket->perm_x = x;
+
+               /* optimize common r=0 case */
+               if (pr == 0) {
+                       s = crush_hash32_3(bucket->hash, x, bucket->id, 0) %
+                               bucket->size;
+                       bucket->perm[0] = s;
+                       bucket->perm_n = 0xffff;   /* magic value, see below */
+                       goto out;
+               }
+
+               for (i = 0; i < bucket->size; i++)
+                       bucket->perm[i] = i;
+               bucket->perm_n = 0;
+       } else if (bucket->perm_n == 0xffff) {
+               /* clean up after the r=0 case above */
+               for (i = 1; i < bucket->size; i++)
+                       bucket->perm[i] = i;
+               bucket->perm[bucket->perm[0]] = 0;
+               bucket->perm_n = 1;
+       }
+
+       /* calculate permutation up to pr */
+       for (i = 0; i < bucket->perm_n; i++)
+               dprintk(" perm_choose have %d: %d\n", i, bucket->perm[i]);
+       while (bucket->perm_n <= pr) {
+               unsigned p = bucket->perm_n;
+               /* no point in swapping the final entry */
+               if (p < bucket->size - 1) {
+                       i = crush_hash32_3(bucket->hash, x, bucket->id, p) %
+                               (bucket->size - p);
+                       if (i) {
+                               unsigned t = bucket->perm[p + i];
+                               bucket->perm[p + i] = bucket->perm[p];
+                               bucket->perm[p] = t;
+                       }
+                       dprintk(" perm_choose swap %d with %d\n", p, p+i);
+               }
+               bucket->perm_n++;
+       }
+       for (i = 0; i < bucket->size; i++)
+               dprintk(" perm_choose  %d: %d\n", i, bucket->perm[i]);
+
+       s = bucket->perm[pr];
+out:
+       dprintk(" perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", bucket->id,
+               bucket->size, x, r, pr, s);
+       return bucket->items[s];
+}
+
+/* uniform */
+static int bucket_uniform_choose(struct crush_bucket_uniform *bucket,
+                                int x, int r)
+{
+       return bucket_perm_choose(&bucket->h, x, r);
+}
+
+/* list */
+static int bucket_list_choose(struct crush_bucket_list *bucket,
+                             int x, int r)
+{
+       int i;
+
+       for (i = bucket->h.size-1; i >= 0; i--) {
+               __u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i],
+                                        r, bucket->h.id);
+               w &= 0xffff;
+               dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
+                       "sw %x rand %llx",
+                       i, x, r, bucket->h.items[i], bucket->item_weights[i],
+                       bucket->sum_weights[i], w);
+               w *= bucket->sum_weights[i];
+               w = w >> 16;
+               /*dprintk(" scaled %llx\n", w);*/
+               if (w < bucket->item_weights[i])
+                       return bucket->h.items[i];
+       }
+
+       BUG_ON(1);
+       return 0;
+}
+
+
+/* (binary) tree */
+static int height(int n)
+{
+       int h = 0;
+       while ((n & 1) == 0) {
+               h++;
+               n = n >> 1;
+       }
+       return h;
+}
+
+static int left(int x)
+{
+       int h = height(x);
+       return x - (1 << (h-1));
+}
+
+static int right(int x)
+{
+       int h = height(x);
+       return x + (1 << (h-1));
+}
+
+static int terminal(int x)
+{
+       return x & 1;
+}
+
+static int bucket_tree_choose(struct crush_bucket_tree *bucket,
+                             int x, int r)
+{
+       int n, l;
+       __u32 w;
+       __u64 t;
+
+       /* start at root */
+       n = bucket->num_nodes >> 1;
+
+       while (!terminal(n)) {
+               /* pick point in [0, w) */
+               w = bucket->node_weights[n];
+               t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r,
+                                         bucket->h.id) * (__u64)w;
+               t = t >> 32;
+
+               /* descend to the left or right? */
+               l = left(n);
+               if (t < bucket->node_weights[l])
+                       n = l;
+               else
+                       n = right(n);
+       }
+
+       return bucket->h.items[n >> 1];
+}
+
+
+/* straw */
+
+static int bucket_straw_choose(struct crush_bucket_straw *bucket,
+                              int x, int r)
+{
+       int i;
+       int high = 0;
+       __u64 high_draw = 0;
+       __u64 draw;
+
+       for (i = 0; i < bucket->h.size; i++) {
+               draw = crush_hash32_3(bucket->h.hash, x, bucket->h.items[i], r);
+               draw &= 0xffff;
+               draw *= bucket->straws[i];
+               if (i == 0 || draw > high_draw) {
+                       high = i;
+                       high_draw = draw;
+               }
+       }
+       return bucket->h.items[high];
+}
+
+static int crush_bucket_choose(struct crush_bucket *in, int x, int r)
+{
+       dprintk("choose %d x=%d r=%d\n", in->id, x, r);
+       switch (in->alg) {
+       case CRUSH_BUCKET_UNIFORM:
+               return bucket_uniform_choose((struct crush_bucket_uniform *)in,
+                                         x, r);
+       case CRUSH_BUCKET_LIST:
+               return bucket_list_choose((struct crush_bucket_list *)in,
+                                         x, r);
+       case CRUSH_BUCKET_TREE:
+               return bucket_tree_choose((struct crush_bucket_tree *)in,
+                                         x, r);
+       case CRUSH_BUCKET_STRAW:
+               return bucket_straw_choose((struct crush_bucket_straw *)in,
+                                          x, r);
+       default:
+               BUG_ON(1);
+               return in->items[0];
+       }
+}
+
+/*
+ * true if device is marked "out" (failed, fully offloaded)
+ * of the cluster
+ */
+static int is_out(struct crush_map *map, __u32 *weight, int item, int x)
+{
+       if (weight[item] >= 0x1000)
+               return 0;
+       if (weight[item] == 0)
+               return 1;
+       if ((crush_hash32_2(CRUSH_HASH_RJENKINS1, x, item) & 0xffff)
+           < weight[item])
+               return 0;
+       return 1;
+}
+
+/**
+ * crush_choose - choose numrep distinct items of given type
+ * @map: the crush_map
+ * @bucket: the bucket we are choose an item from
+ * @x: crush input value
+ * @numrep: the number of items to choose
+ * @type: the type of item to choose
+ * @out: pointer to output vector
+ * @outpos: our position in that vector
+ * @firstn: true if choosing "first n" items, false if choosing "indep"
+ * @recurse_to_leaf: true if we want one device under each item of given type
+ * @out2: second output vector for leaf items (if @recurse_to_leaf)
+ */
+static int crush_choose(struct crush_map *map,
+                       struct crush_bucket *bucket,
+                       __u32 *weight,
+                       int x, int numrep, int type,
+                       int *out, int outpos,
+                       int firstn, int recurse_to_leaf,
+                       int *out2)
+{
+       int rep;
+       int ftotal, flocal;
+       int retry_descent, retry_bucket, skip_rep;
+       struct crush_bucket *in = bucket;
+       int r;
+       int i;
+       int item = 0;
+       int itemtype;
+       int collide, reject;
+       const int orig_tries = 5; /* attempts before we fall back to search */
+       dprintk("choose bucket %d x %d outpos %d\n", bucket->id, x, outpos);
+
+       for (rep = outpos; rep < numrep; rep++) {
+               /* keep trying until we get a non-out, non-colliding item */
+               ftotal = 0;
+               skip_rep = 0;
+               do {
+                       retry_descent = 0;
+                       in = bucket;               /* initial bucket */
+
+                       /* choose through intervening buckets */
+                       flocal = 0;
+                       do {
+                               collide = 0;
+                               retry_bucket = 0;
+                               r = rep;
+                               if (in->alg == CRUSH_BUCKET_UNIFORM) {
+                                       /* be careful */
+                                       if (firstn || numrep >= in->size)
+                                               /* r' = r + f_total */
+                                               r += ftotal;
+                                       else if (in->size % numrep == 0)
+                                               /* r'=r+(n+1)*f_local */
+                                               r += (numrep+1) *
+                                                       (flocal+ftotal);
+                                       else
+                                               /* r' = r + n*f_local */
+                                               r += numrep * (flocal+ftotal);
+                               } else {
+                                       if (firstn)
+                                               /* r' = r + f_total */
+                                               r += ftotal;
+                                       else
+                                               /* r' = r + n*f_local */
+                                               r += numrep * (flocal+ftotal);
+                               }
+
+                               /* bucket choose */
+                               if (in->size == 0) {
+                                       reject = 1;
+                                       goto reject;
+                               }
+                               if (flocal >= (in->size>>1) &&
+                                   flocal > orig_tries)
+                                       item = bucket_perm_choose(in, x, r);
+                               else
+                                       item = crush_bucket_choose(in, x, r);
+                               BUG_ON(item >= map->max_devices);
+
+                               /* desired type? */
+                               if (item < 0)
+                                       itemtype = map->buckets[-1-item]->type;
+                               else
+                                       itemtype = 0;
+                               dprintk("  item %d type %d\n", item, itemtype);
+
+                               /* keep going? */
+                               if (itemtype != type) {
+                                       BUG_ON(item >= 0 ||
+                                              (-1-item) >= map->max_buckets);
+                                       in = map->buckets[-1-item];
+                                       continue;
+                               }
+
+                               /* collision? */
+                               for (i = 0; i < outpos; i++) {
+                                       if (out[i] == item) {
+                                               collide = 1;
+                                               break;
+                                       }
+                               }
+
+                               if (recurse_to_leaf &&
+                                   item < 0 &&
+                                   crush_choose(map, map->buckets[-1-item],
+                                                weight,
+                                                x, outpos+1, 0,
+                                                out2, outpos,
+                                                firstn, 0, NULL) <= outpos) {
+                                       reject = 1;
+                               } else {
+                                       /* out? */
+                                       if (itemtype == 0)
+                                               reject = is_out(map, weight,
+                                                               item, x);
+                                       else
+                                               reject = 0;
+                               }
+
+reject:
+                               if (reject || collide) {
+                                       ftotal++;
+                                       flocal++;
+
+                                       if (collide && flocal < 3)
+                                               /* retry locally a few times */
+                                               retry_bucket = 1;
+                                       else if (flocal < in->size + orig_tries)
+                                               /* exhaustive bucket search */
+                                               retry_bucket = 1;
+                                       else if (ftotal < 20)
+                                               /* then retry descent */
+                                               retry_descent = 1;
+                                       else
+                                               /* else give up */
+                                               skip_rep = 1;
+                                       dprintk("  reject %d  collide %d  "
+                                               "ftotal %d  flocal %d\n",
+                                               reject, collide, ftotal,
+                                               flocal);
+                               }
+                       } while (retry_bucket);
+               } while (retry_descent);
+
+               if (skip_rep) {
+                       dprintk("skip rep\n");
+                       continue;
+               }
+
+               dprintk("choose got %d\n", item);
+               out[outpos] = item;
+               outpos++;
+       }
+
+       dprintk("choose returns %d\n", outpos);
+       return outpos;
+}
+
+
+/**
+ * crush_do_rule - calculate a mapping with the given input and rule
+ * @map: the crush_map
+ * @ruleno: the rule id
+ * @x: hash input
+ * @result: pointer to result vector
+ * @result_max: maximum result size
+ * @force: force initial replica choice; -1 for none
+ */
+int crush_do_rule(struct crush_map *map,
+                 int ruleno, int x, int *result, int result_max,
+                 int force, __u32 *weight)
+{
+       int result_len;
+       int force_context[CRUSH_MAX_DEPTH];
+       int force_pos = -1;
+       int a[CRUSH_MAX_SET];
+       int b[CRUSH_MAX_SET];
+       int c[CRUSH_MAX_SET];
+       int recurse_to_leaf;
+       int *w;
+       int wsize = 0;
+       int *o;
+       int osize;
+       int *tmp;
+       struct crush_rule *rule;
+       int step;
+       int i, j;
+       int numrep;
+       int firstn;
+       int rc = -1;
+
+       BUG_ON(ruleno >= map->max_rules);
+
+       rule = map->rules[ruleno];
+       result_len = 0;
+       w = a;
+       o = b;
+
+       /*
+        * determine hierarchical context of force, if any.  note
+        * that this may or may not correspond to the specific types
+        * referenced by the crush rule.
+        */
+       if (force >= 0) {
+               if (force >= map->max_devices ||
+                   map->device_parents[force] == 0) {
+                       /*dprintk("CRUSH: forcefed device dne\n");*/
+                       rc = -1;  /* force fed device dne */
+                       goto out;
+               }
+               if (!is_out(map, weight, force, x)) {
+                       while (1) {
+                               force_context[++force_pos] = force;
+                               if (force >= 0)
+                                       force = map->device_parents[force];
+                               else
+                                       force = map->bucket_parents[-1-force];
+                               if (force == 0)
+                                       break;
+                       }
+               }
+       }
+
+       for (step = 0; step < rule->len; step++) {
+               firstn = 0;
+               switch (rule->steps[step].op) {
+               case CRUSH_RULE_TAKE:
+                       w[0] = rule->steps[step].arg1;
+                       if (force_pos >= 0) {
+                               BUG_ON(force_context[force_pos] != w[0]);
+                               force_pos--;
+                       }
+                       wsize = 1;
+                       break;
+
+               case CRUSH_RULE_CHOOSE_LEAF_FIRSTN:
+               case CRUSH_RULE_CHOOSE_FIRSTN:
+                       firstn = 1;
+               case CRUSH_RULE_CHOOSE_LEAF_INDEP:
+               case CRUSH_RULE_CHOOSE_INDEP:
+                       BUG_ON(wsize == 0);
+
+                       recurse_to_leaf =
+                               rule->steps[step].op ==
+                                CRUSH_RULE_CHOOSE_LEAF_FIRSTN ||
+                               rule->steps[step].op ==
+                               CRUSH_RULE_CHOOSE_LEAF_INDEP;
+
+                       /* reset output */
+                       osize = 0;
+
+                       for (i = 0; i < wsize; i++) {
+                               /*
+                                * see CRUSH_N, CRUSH_N_MINUS macros.
+                                * basically, numrep <= 0 means relative to
+                                * the provided result_max
+                                */
+                               numrep = rule->steps[step].arg1;
+                               if (numrep <= 0) {
+                                       numrep += result_max;
+                                       if (numrep <= 0)
+                                               continue;
+                               }
+                               j = 0;
+                               if (osize == 0 && force_pos >= 0) {
+                                       /* skip any intermediate types */
+                                       while (force_pos &&
+                                              force_context[force_pos] < 0 &&
+                                              rule->steps[step].arg2 !=
+                                              map->buckets[-1 -
+                                              force_context[force_pos]]->type)
+                                               force_pos--;
+                                       o[osize] = force_context[force_pos];
+                                       if (recurse_to_leaf)
+                                               c[osize] = force_context[0];
+                                       j++;
+                                       force_pos--;
+                               }
+                               osize += crush_choose(map,
+                                                     map->buckets[-1-w[i]],
+                                                     weight,
+                                                     x, numrep,
+                                                     rule->steps[step].arg2,
+                                                     o+osize, j,
+                                                     firstn,
+                                                     recurse_to_leaf, c+osize);
+                       }
+
+                       if (recurse_to_leaf)
+                               /* copy final _leaf_ values to output set */
+                               memcpy(o, c, osize*sizeof(*o));
+
+                       /* swap t and w arrays */
+                       tmp = o;
+                       o = w;
+                       w = tmp;
+                       wsize = osize;
+                       break;
+
+
+               case CRUSH_RULE_EMIT:
+                       for (i = 0; i < wsize && result_len < result_max; i++) {
+                               result[result_len] = w[i];
+                               result_len++;
+                       }
+                       wsize = 0;
+                       break;
+
+               default:
+                       BUG_ON(1);
+               }
+       }
+       rc = result_len;
+
+out:
+       return rc;
+}
+
+
diff --git a/fs/ceph/crush/mapper.h b/fs/ceph/crush/mapper.h
new file mode 100644 (file)
index 0000000..98e9004
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _CRUSH_MAPPER_H
+#define _CRUSH_MAPPER_H
+
+/*
+ * CRUSH functions for find rules and then mapping an input to an
+ * output set.
+ *
+ * LGPL2
+ */
+
+#include "crush.h"
+
+extern int crush_find_rule(struct crush_map *map, int pool, int type, int size);
+extern int crush_do_rule(struct crush_map *map,
+                        int ruleno,
+                        int x, int *result, int result_max,
+                        int forcefeed,    /* -1 for none */
+                        __u32 *weights);
+
+#endif
diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
new file mode 100644 (file)
index 0000000..291ac28
--- /dev/null
@@ -0,0 +1,408 @@
+
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include <crypto/hash.h>
+
+#include "crypto.h"
+#include "decode.h"
+
+int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
+{
+       if (*p + sizeof(u16) + sizeof(key->created) +
+           sizeof(u16) + key->len > end)
+               return -ERANGE;
+       ceph_encode_16(p, key->type);
+       ceph_encode_copy(p, &key->created, sizeof(key->created));
+       ceph_encode_16(p, key->len);
+       ceph_encode_copy(p, key->key, key->len);
+       return 0;
+}
+
+int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
+{
+       ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
+       key->type = ceph_decode_16(p);
+       ceph_decode_copy(p, &key->created, sizeof(key->created));
+       key->len = ceph_decode_16(p);
+       ceph_decode_need(p, end, key->len, bad);
+       key->key = kmalloc(key->len, GFP_NOFS);
+       if (!key->key)
+               return -ENOMEM;
+       ceph_decode_copy(p, key->key, key->len);
+       return 0;
+
+bad:
+       dout("failed to decode crypto key\n");
+       return -EINVAL;
+}
+
+int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
+{
+       int inlen = strlen(inkey);
+       int blen = inlen * 3 / 4;
+       void *buf, *p;
+       int ret;
+
+       dout("crypto_key_unarmor %s\n", inkey);
+       buf = kmalloc(blen, GFP_NOFS);
+       if (!buf)
+               return -ENOMEM;
+       blen = ceph_unarmor(buf, inkey, inkey+inlen);
+       if (blen < 0) {
+               kfree(buf);
+               return blen;
+       }
+
+       p = buf;
+       ret = ceph_crypto_key_decode(key, &p, p + blen);
+       kfree(buf);
+       if (ret)
+               return ret;
+       dout("crypto_key_unarmor key %p type %d len %d\n", key,
+            key->type, key->len);
+       return 0;
+}
+
+
+
+#define AES_KEY_SIZE 16
+
+static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void)
+{
+       return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+}
+
+const u8 *aes_iv = "cephsageyudagreg";
+
+int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len,
+                    const void *src, size_t src_len)
+{
+       struct scatterlist sg_in[2], sg_out[1];
+       struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
+       struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
+       int ret;
+       void *iv;
+       int ivsize;
+       size_t zero_padding = (0x10 - (src_len & 0x0f));
+       char pad[16];
+
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+
+       memset(pad, zero_padding, zero_padding);
+
+       *dst_len = src_len + zero_padding;
+
+       crypto_blkcipher_setkey((void *)tfm, key, key_len);
+       sg_init_table(sg_in, 2);
+       sg_set_buf(&sg_in[0], src, src_len);
+       sg_set_buf(&sg_in[1], pad, zero_padding);
+       sg_init_table(sg_out, 1);
+       sg_set_buf(sg_out, dst, *dst_len);
+       iv = crypto_blkcipher_crt(tfm)->iv;
+       ivsize = crypto_blkcipher_ivsize(tfm);
+
+       memcpy(iv, aes_iv, ivsize);
+       /*
+       print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
+                      key, key_len, 1);
+       print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
+                       src, src_len, 1);
+       print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
+                       pad, zero_padding, 1);
+       */
+       ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
+                                    src_len + zero_padding);
+       crypto_free_blkcipher(tfm);
+       if (ret < 0)
+               pr_err("ceph_aes_crypt failed %d\n", ret);
+       /*
+       print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
+                      dst, *dst_len, 1);
+       */
+       return 0;
+}
+
+int ceph_aes_encrypt2(const void *key, int key_len, void *dst, size_t *dst_len,
+                     const void *src1, size_t src1_len,
+                     const void *src2, size_t src2_len)
+{
+       struct scatterlist sg_in[3], sg_out[1];
+       struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
+       struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
+       int ret;
+       void *iv;
+       int ivsize;
+       size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
+       char pad[16];
+
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+
+       memset(pad, zero_padding, zero_padding);
+
+       *dst_len = src1_len + src2_len + zero_padding;
+
+       crypto_blkcipher_setkey((void *)tfm, key, key_len);
+       sg_init_table(sg_in, 3);
+       sg_set_buf(&sg_in[0], src1, src1_len);
+       sg_set_buf(&sg_in[1], src2, src2_len);
+       sg_set_buf(&sg_in[2], pad, zero_padding);
+       sg_init_table(sg_out, 1);
+       sg_set_buf(sg_out, dst, *dst_len);
+       iv = crypto_blkcipher_crt(tfm)->iv;
+       ivsize = crypto_blkcipher_ivsize(tfm);
+
+       memcpy(iv, aes_iv, ivsize);
+       /*
+       print_hex_dump(KERN_ERR, "enc  key: ", DUMP_PREFIX_NONE, 16, 1,
+                      key, key_len, 1);
+       print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
+                       src1, src1_len, 1);
+       print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
+                       src2, src2_len, 1);
+       print_hex_dump(KERN_ERR, "enc  pad: ", DUMP_PREFIX_NONE, 16, 1,
+                       pad, zero_padding, 1);
+       */
+       ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
+                                    src1_len + src2_len + zero_padding);
+       crypto_free_blkcipher(tfm);
+       if (ret < 0)
+               pr_err("ceph_aes_crypt2 failed %d\n", ret);
+       /*
+       print_hex_dump(KERN_ERR, "enc  out: ", DUMP_PREFIX_NONE, 16, 1,
+                      dst, *dst_len, 1);
+       */
+       return 0;
+}
+
+int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len,
+                    const void *src, size_t src_len)
+{
+       struct scatterlist sg_in[1], sg_out[2];
+       struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
+       struct blkcipher_desc desc = { .tfm = tfm };
+       char pad[16];
+       void *iv;
+       int ivsize;
+       int ret;
+       int last_byte;
+
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+
+       crypto_blkcipher_setkey((void *)tfm, key, key_len);
+       sg_init_table(sg_in, 1);
+       sg_init_table(sg_out, 2);
+       sg_set_buf(sg_in, src, src_len);
+       sg_set_buf(&sg_out[0], dst, *dst_len);
+       sg_set_buf(&sg_out[1], pad, sizeof(pad));
+
+       iv = crypto_blkcipher_crt(tfm)->iv;
+       ivsize = crypto_blkcipher_ivsize(tfm);
+
+       memcpy(iv, aes_iv, ivsize);
+
+       /*
+       print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
+                      key, key_len, 1);
+       print_hex_dump(KERN_ERR, "dec  in: ", DUMP_PREFIX_NONE, 16, 1,
+                      src, src_len, 1);
+       */
+
+       ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
+       crypto_free_blkcipher(tfm);
+       if (ret < 0) {
+               pr_err("ceph_aes_decrypt failed %d\n", ret);
+               return ret;
+       }
+
+       if (src_len <= *dst_len)
+               last_byte = ((char *)dst)[src_len - 1];
+       else
+               last_byte = pad[src_len - *dst_len - 1];
+       if (last_byte <= 16 && src_len >= last_byte) {
+               *dst_len = src_len - last_byte;
+       } else {
+               pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
+                      last_byte, (int)src_len);
+               return -EPERM;  /* bad padding */
+       }
+       /*
+       print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
+                      dst, *dst_len, 1);
+       */
+       return 0;
+}
+
+int ceph_aes_decrypt2(const void *key, int key_len,
+                     void *dst1, size_t *dst1_len,
+                     void *dst2, size_t *dst2_len,
+                     const void *src, size_t src_len)
+{
+       struct scatterlist sg_in[1], sg_out[3];
+       struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
+       struct blkcipher_desc desc = { .tfm = tfm };
+       char pad[16];
+       void *iv;
+       int ivsize;
+       int ret;
+       int last_byte;
+
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+
+       sg_init_table(sg_in, 1);
+       sg_set_buf(sg_in, src, src_len);
+       sg_init_table(sg_out, 3);
+       sg_set_buf(&sg_out[0], dst1, *dst1_len);
+       sg_set_buf(&sg_out[1], dst2, *dst2_len);
+       sg_set_buf(&sg_out[2], pad, sizeof(pad));
+
+       crypto_blkcipher_setkey((void *)tfm, key, key_len);
+       iv = crypto_blkcipher_crt(tfm)->iv;
+       ivsize = crypto_blkcipher_ivsize(tfm);
+
+       memcpy(iv, aes_iv, ivsize);
+
+       /*
+       print_hex_dump(KERN_ERR, "dec  key: ", DUMP_PREFIX_NONE, 16, 1,
+                      key, key_len, 1);
+       print_hex_dump(KERN_ERR, "dec   in: ", DUMP_PREFIX_NONE, 16, 1,
+                      src, src_len, 1);
+       */
+
+       ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
+       crypto_free_blkcipher(tfm);
+       if (ret < 0) {
+               pr_err("ceph_aes_decrypt failed %d\n", ret);
+               return ret;
+       }
+
+       if (src_len <= *dst1_len)
+               last_byte = ((char *)dst1)[src_len - 1];
+       else if (src_len <= *dst1_len + *dst2_len)
+               last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
+       else
+               last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
+       if (last_byte <= 16 && src_len >= last_byte) {
+               src_len -= last_byte;
+       } else {
+               pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
+                      last_byte, (int)src_len);
+               return -EPERM;  /* bad padding */
+       }
+
+       if (src_len < *dst1_len) {
+               *dst1_len = src_len;
+               *dst2_len = 0;
+       } else {
+               *dst2_len = src_len - *dst1_len;
+       }
+       /*
+       print_hex_dump(KERN_ERR, "dec  out1: ", DUMP_PREFIX_NONE, 16, 1,
+                      dst1, *dst1_len, 1);
+       print_hex_dump(KERN_ERR, "dec  out2: ", DUMP_PREFIX_NONE, 16, 1,
+                      dst2, *dst2_len, 1);
+       */
+
+       return 0;
+}
+
+
+int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
+                const void *src, size_t src_len)
+{
+       switch (secret->type) {
+       case CEPH_CRYPTO_NONE:
+               if (*dst_len < src_len)
+                       return -ERANGE;
+               memcpy(dst, src, src_len);
+               *dst_len = src_len;
+               return 0;
+
+       case CEPH_CRYPTO_AES:
+               return ceph_aes_decrypt(secret->key, secret->len, dst,
+                                       dst_len, src, src_len);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+int ceph_decrypt2(struct ceph_crypto_key *secret,
+                       void *dst1, size_t *dst1_len,
+                       void *dst2, size_t *dst2_len,
+                       const void *src, size_t src_len)
+{
+       size_t t;
+
+       switch (secret->type) {
+       case CEPH_CRYPTO_NONE:
+               if (*dst1_len + *dst2_len < src_len)
+                       return -ERANGE;
+               t = min(*dst1_len, src_len);
+               memcpy(dst1, src, t);
+               *dst1_len = t;
+               src += t;
+               src_len -= t;
+               if (src_len) {
+                       t = min(*dst2_len, src_len);
+                       memcpy(dst2, src, t);
+                       *dst2_len = t;
+               }
+               return 0;
+
+       case CEPH_CRYPTO_AES:
+               return ceph_aes_decrypt2(secret->key, secret->len,
+                                        dst1, dst1_len, dst2, dst2_len,
+                                        src, src_len);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
+                const void *src, size_t src_len)
+{
+       switch (secret->type) {
+       case CEPH_CRYPTO_NONE:
+               if (*dst_len < src_len)
+                       return -ERANGE;
+               memcpy(dst, src, src_len);
+               *dst_len = src_len;
+               return 0;
+
+       case CEPH_CRYPTO_AES:
+               return ceph_aes_encrypt(secret->key, secret->len, dst,
+                                       dst_len, src, src_len);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
+                 const void *src1, size_t src1_len,
+                 const void *src2, size_t src2_len)
+{
+       switch (secret->type) {
+       case CEPH_CRYPTO_NONE:
+               if (*dst_len < src1_len + src2_len)
+                       return -ERANGE;
+               memcpy(dst, src1, src1_len);
+               memcpy(dst + src1_len, src2, src2_len);
+               *dst_len = src1_len + src2_len;
+               return 0;
+
+       case CEPH_CRYPTO_AES:
+               return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
+                                        src1, src1_len, src2, src2_len);
+
+       default:
+               return -EINVAL;
+       }
+}
diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h
new file mode 100644 (file)
index 0000000..40b502e
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _FS_CEPH_CRYPTO_H
+#define _FS_CEPH_CRYPTO_H
+
+#include "types.h"
+#include "buffer.h"
+
+/*
+ * cryptographic secret
+ */
+struct ceph_crypto_key {
+       int type;
+       struct ceph_timespec created;
+       int len;
+       void *key;
+};
+
+static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
+{
+       kfree(key->key);
+}
+
+extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
+                                 void **p, void *end);
+extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
+                                 void **p, void *end);
+extern int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *in);
+
+/* crypto.c */
+extern int ceph_decrypt(struct ceph_crypto_key *secret,
+                       void *dst, size_t *dst_len,
+                       const void *src, size_t src_len);
+extern int ceph_encrypt(struct ceph_crypto_key *secret,
+                       void *dst, size_t *dst_len,
+                       const void *src, size_t src_len);
+extern int ceph_decrypt2(struct ceph_crypto_key *secret,
+                       void *dst1, size_t *dst1_len,
+                       void *dst2, size_t *dst2_len,
+                       const void *src, size_t src_len);
+extern int ceph_encrypt2(struct ceph_crypto_key *secret,
+                        void *dst, size_t *dst_len,
+                        const void *src1, size_t src1_len,
+                        const void *src2, size_t src2_len);
+
+/* armor.c */
+extern int ceph_armor(char *dst, const void *src, const void *end);
+extern int ceph_unarmor(void *dst, const char *src, const char *end);
+
+#endif
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
new file mode 100644 (file)
index 0000000..e159f14
--- /dev/null
@@ -0,0 +1,483 @@
+#include "ceph_debug.h"
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "super.h"
+#include "mds_client.h"
+#include "mon_client.h"
+#include "auth.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * Implement /sys/kernel/debug/ceph fun
+ *
+ * /sys/kernel/debug/ceph/client*  - an instance of the ceph client
+ *      .../osdmap      - current osdmap
+ *      .../mdsmap      - current mdsmap
+ *      .../monmap      - current monmap
+ *      .../osdc        - active osd requests
+ *      .../mdsc        - active mds requests
+ *      .../monc        - mon client state
+ *      .../dentry_lru  - dump contents of dentry lru
+ *      .../caps        - expose cap (reservation) stats
+ *      .../bdi         - symlink to ../../bdi/something
+ */
+
+static struct dentry *ceph_debugfs_dir;
+
+static int monmap_show(struct seq_file *s, void *p)
+{
+       int i;
+       struct ceph_client *client = s->private;
+
+       if (client->monc.monmap == NULL)
+               return 0;
+
+       seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
+       for (i = 0; i < client->monc.monmap->num_mon; i++) {
+               struct ceph_entity_inst *inst =
+                       &client->monc.monmap->mon_inst[i];
+
+               seq_printf(s, "\t%s%lld\t%s\n",
+                          ENTITY_NAME(inst->name),
+                          pr_addr(&inst->addr.in_addr));
+       }
+       return 0;
+}
+
+static int mdsmap_show(struct seq_file *s, void *p)
+{
+       int i;
+       struct ceph_client *client = s->private;
+
+       if (client->mdsc.mdsmap == NULL)
+               return 0;
+       seq_printf(s, "epoch %d\n", client->mdsc.mdsmap->m_epoch);
+       seq_printf(s, "root %d\n", client->mdsc.mdsmap->m_root);
+       seq_printf(s, "session_timeout %d\n",
+                      client->mdsc.mdsmap->m_session_timeout);
+       seq_printf(s, "session_autoclose %d\n",
+                      client->mdsc.mdsmap->m_session_autoclose);
+       for (i = 0; i < client->mdsc.mdsmap->m_max_mds; i++) {
+               struct ceph_entity_addr *addr =
+                       &client->mdsc.mdsmap->m_info[i].addr;
+               int state = client->mdsc.mdsmap->m_info[i].state;
+
+               seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, pr_addr(&addr->in_addr),
+                              ceph_mds_state_name(state));
+       }
+       return 0;
+}
+
+static int osdmap_show(struct seq_file *s, void *p)
+{
+       int i;
+       struct ceph_client *client = s->private;
+       struct rb_node *n;
+
+       if (client->osdc.osdmap == NULL)
+               return 0;
+       seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
+       seq_printf(s, "flags%s%s\n",
+                  (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
+                  " NEARFULL" : "",
+                  (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
+                  " FULL" : "");
+       for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
+               struct ceph_pg_pool_info *pool =
+                       rb_entry(n, struct ceph_pg_pool_info, node);
+               seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
+                          pool->id, pool->v.pg_num, pool->pg_num_mask,
+                          pool->v.lpg_num, pool->lpg_num_mask);
+       }
+       for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
+               struct ceph_entity_addr *addr =
+                       &client->osdc.osdmap->osd_addr[i];
+               int state = client->osdc.osdmap->osd_state[i];
+               char sb[64];
+
+               seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
+                          i, pr_addr(&addr->in_addr),
+                          ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
+                          ceph_osdmap_state_str(sb, sizeof(sb), state));
+       }
+       return 0;
+}
+
+static int monc_show(struct seq_file *s, void *p)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_mon_statfs_request *req;
+       struct ceph_mon_client *monc = &client->monc;
+       struct rb_node *rp;
+
+       mutex_lock(&monc->mutex);
+
+       if (monc->have_mdsmap)
+               seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
+       if (monc->have_osdmap)
+               seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
+       if (monc->want_next_osdmap)
+               seq_printf(s, "want next osdmap\n");
+
+       for (rp = rb_first(&monc->statfs_request_tree); rp; rp = rb_next(rp)) {
+               req = rb_entry(rp, struct ceph_mon_statfs_request, node);
+               seq_printf(s, "%lld statfs\n", req->tid);
+       }
+
+       mutex_unlock(&monc->mutex);
+       return 0;
+}
+
+static int mdsc_show(struct seq_file *s, void *p)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       struct rb_node *rp;
+       int pathlen;
+       u64 pathbase;
+       char *path;
+
+       mutex_lock(&mdsc->mutex);
+       for (rp = rb_first(&mdsc->request_tree); rp; rp = rb_next(rp)) {
+               req = rb_entry(rp, struct ceph_mds_request, r_node);
+
+               if (req->r_request)
+                       seq_printf(s, "%lld\tmds%d\t", req->r_tid, req->r_mds);
+               else
+                       seq_printf(s, "%lld\t(no request)\t", req->r_tid);
+
+               seq_printf(s, "%s", ceph_mds_op_name(req->r_op));
+
+               if (req->r_got_unsafe)
+                       seq_printf(s, "\t(unsafe)");
+               else
+                       seq_printf(s, "\t");
+
+               if (req->r_inode) {
+                       seq_printf(s, " #%llx", ceph_ino(req->r_inode));
+               } else if (req->r_dentry) {
+                       path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
+                                                   &pathbase, 0);
+                       spin_lock(&req->r_dentry->d_lock);
+                       seq_printf(s, " #%llx/%.*s (%s)",
+                                  ceph_ino(req->r_dentry->d_parent->d_inode),
+                                  req->r_dentry->d_name.len,
+                                  req->r_dentry->d_name.name,
+                                  path ? path : "");
+                       spin_unlock(&req->r_dentry->d_lock);
+                       kfree(path);
+               } else if (req->r_path1) {
+                       seq_printf(s, " #%llx/%s", req->r_ino1.ino,
+                                  req->r_path1);
+               }
+
+               if (req->r_old_dentry) {
+                       path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen,
+                                                   &pathbase, 0);
+                       spin_lock(&req->r_old_dentry->d_lock);
+                       seq_printf(s, " #%llx/%.*s (%s)",
+                          ceph_ino(req->r_old_dentry->d_parent->d_inode),
+                                  req->r_old_dentry->d_name.len,
+                                  req->r_old_dentry->d_name.name,
+                                  path ? path : "");
+                       spin_unlock(&req->r_old_dentry->d_lock);
+                       kfree(path);
+               } else if (req->r_path2) {
+                       if (req->r_ino2.ino)
+                               seq_printf(s, " #%llx/%s", req->r_ino2.ino,
+                                          req->r_path2);
+                       else
+                               seq_printf(s, " %s", req->r_path2);
+               }
+
+               seq_printf(s, "\n");
+       }
+       mutex_unlock(&mdsc->mutex);
+
+       return 0;
+}
+
+static int osdc_show(struct seq_file *s, void *pp)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_osd_client *osdc = &client->osdc;
+       struct rb_node *p;
+
+       mutex_lock(&osdc->request_mutex);
+       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+               struct ceph_osd_request *req;
+               struct ceph_osd_request_head *head;
+               struct ceph_osd_op *op;
+               int num_ops;
+               int opcode, olen;
+               int i;
+
+               req = rb_entry(p, struct ceph_osd_request, r_node);
+
+               seq_printf(s, "%lld\tosd%d\t%d.%x\t", req->r_tid,
+                          req->r_osd ? req->r_osd->o_osd : -1,
+                          le32_to_cpu(req->r_pgid.pool),
+                          le16_to_cpu(req->r_pgid.ps));
+
+               head = req->r_request->front.iov_base;
+               op = (void *)(head + 1);
+
+               num_ops = le16_to_cpu(head->num_ops);
+               olen = le32_to_cpu(head->object_len);
+               seq_printf(s, "%.*s", olen,
+                          (const char *)(head->ops + num_ops));
+
+               if (req->r_reassert_version.epoch)
+                       seq_printf(s, "\t%u'%llu",
+                          (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
+                          le64_to_cpu(req->r_reassert_version.version));
+               else
+                       seq_printf(s, "\t");
+
+               for (i = 0; i < num_ops; i++) {
+                       opcode = le16_to_cpu(op->op);
+                       seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
+                       op++;
+               }
+
+               seq_printf(s, "\n");
+       }
+       mutex_unlock(&osdc->request_mutex);
+       return 0;
+}
+
+static int caps_show(struct seq_file *s, void *p)
+{
+       struct ceph_client *client = p;
+       int total, avail, used, reserved, min;
+
+       ceph_reservation_status(client, &total, &avail, &used, &reserved, &min);
+       seq_printf(s, "total\t\t%d\n"
+                  "avail\t\t%d\n"
+                  "used\t\t%d\n"
+                  "reserved\t%d\n"
+                  "min\t%d\n",
+                  total, avail, used, reserved, min);
+       return 0;
+}
+
+static int dentry_lru_show(struct seq_file *s, void *ptr)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_dentry_info *di;
+
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_for_each_entry(di, &mdsc->dentry_lru, lru) {
+               struct dentry *dentry = di->dentry;
+               seq_printf(s, "%p %p\t%.*s\n",
+                          di, dentry, dentry->d_name.len, dentry->d_name.name);
+       }
+       spin_unlock(&mdsc->dentry_lru_lock);
+
+       return 0;
+}
+
+#define DEFINE_SHOW_FUNC(name)                                                 \
+static int name##_open(struct inode *inode, struct file *file)         \
+{                                                                      \
+       struct seq_file *sf;                                            \
+       int ret;                                                        \
+                                                                       \
+       ret = single_open(file, name, NULL);                            \
+       sf = file->private_data;                                        \
+       sf->private = inode->i_private;                                 \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static const struct file_operations name##_fops = {                    \
+       .open           = name##_open,                                  \
+       .read           = seq_read,                                     \
+       .llseek         = seq_lseek,                                    \
+       .release        = single_release,                               \
+};
+
+DEFINE_SHOW_FUNC(monmap_show)
+DEFINE_SHOW_FUNC(mdsmap_show)
+DEFINE_SHOW_FUNC(osdmap_show)
+DEFINE_SHOW_FUNC(monc_show)
+DEFINE_SHOW_FUNC(mdsc_show)
+DEFINE_SHOW_FUNC(osdc_show)
+DEFINE_SHOW_FUNC(dentry_lru_show)
+DEFINE_SHOW_FUNC(caps_show)
+
+static int congestion_kb_set(void *data, u64 val)
+{
+       struct ceph_client *client = (struct ceph_client *)data;
+
+       if (client)
+               client->mount_args->congestion_kb = (int)val;
+
+       return 0;
+}
+
+static int congestion_kb_get(void *data, u64 *val)
+{
+       struct ceph_client *client = (struct ceph_client *)data;
+
+       if (client)
+               *val = (u64)client->mount_args->congestion_kb;
+
+       return 0;
+}
+
+
+DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
+                       congestion_kb_set, "%llu\n");
+
+int __init ceph_debugfs_init(void)
+{
+       ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
+       if (!ceph_debugfs_dir)
+               return -ENOMEM;
+       return 0;
+}
+
+void ceph_debugfs_cleanup(void)
+{
+       debugfs_remove(ceph_debugfs_dir);
+}
+
+int ceph_debugfs_client_init(struct ceph_client *client)
+{
+       int ret = 0;
+       char name[80];
+
+       snprintf(name, sizeof(name), FSID_FORMAT ".client%lld",
+                PR_FSID(&client->fsid), client->monc.auth->global_id);
+
+       client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
+       if (!client->debugfs_dir)
+               goto out;
+
+       client->monc.debugfs_file = debugfs_create_file("monc",
+                                                     0600,
+                                                     client->debugfs_dir,
+                                                     client,
+                                                     &monc_show_fops);
+       if (!client->monc.debugfs_file)
+               goto out;
+
+       client->mdsc.debugfs_file = debugfs_create_file("mdsc",
+                                                     0600,
+                                                     client->debugfs_dir,
+                                                     client,
+                                                     &mdsc_show_fops);
+       if (!client->mdsc.debugfs_file)
+               goto out;
+
+       client->osdc.debugfs_file = debugfs_create_file("osdc",
+                                                     0600,
+                                                     client->debugfs_dir,
+                                                     client,
+                                                     &osdc_show_fops);
+       if (!client->osdc.debugfs_file)
+               goto out;
+
+       client->debugfs_monmap = debugfs_create_file("monmap",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &monmap_show_fops);
+       if (!client->debugfs_monmap)
+               goto out;
+
+       client->debugfs_mdsmap = debugfs_create_file("mdsmap",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &mdsmap_show_fops);
+       if (!client->debugfs_mdsmap)
+               goto out;
+
+       client->debugfs_osdmap = debugfs_create_file("osdmap",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &osdmap_show_fops);
+       if (!client->debugfs_osdmap)
+               goto out;
+
+       client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &dentry_lru_show_fops);
+       if (!client->debugfs_dentry_lru)
+               goto out;
+
+       client->debugfs_caps = debugfs_create_file("caps",
+                                                  0400,
+                                                  client->debugfs_dir,
+                                                  client,
+                                                  &caps_show_fops);
+       if (!client->debugfs_caps)
+               goto out;
+
+       client->debugfs_congestion_kb = debugfs_create_file("writeback_congestion_kb",
+                                                  0600,
+                                                  client->debugfs_dir,
+                                                  client,
+                                                  &congestion_kb_fops);
+       if (!client->debugfs_congestion_kb)
+               goto out;
+
+       sprintf(name, "../../bdi/%s", dev_name(client->sb->s_bdi->dev));
+       client->debugfs_bdi = debugfs_create_symlink("bdi", client->debugfs_dir,
+                                                    name);
+
+       return 0;
+
+out:
+       ceph_debugfs_client_cleanup(client);
+       return ret;
+}
+
+void ceph_debugfs_client_cleanup(struct ceph_client *client)
+{
+       debugfs_remove(client->debugfs_bdi);
+       debugfs_remove(client->debugfs_caps);
+       debugfs_remove(client->debugfs_dentry_lru);
+       debugfs_remove(client->debugfs_osdmap);
+       debugfs_remove(client->debugfs_mdsmap);
+       debugfs_remove(client->debugfs_monmap);
+       debugfs_remove(client->osdc.debugfs_file);
+       debugfs_remove(client->mdsc.debugfs_file);
+       debugfs_remove(client->monc.debugfs_file);
+       debugfs_remove(client->debugfs_congestion_kb);
+       debugfs_remove(client->debugfs_dir);
+}
+
+#else  // CONFIG_DEBUG_FS
+
+int __init ceph_debugfs_init(void)
+{
+       return 0;
+}
+
+void ceph_debugfs_cleanup(void)
+{
+}
+
+int ceph_debugfs_client_init(struct ceph_client *client)
+{
+       return 0;
+}
+
+void ceph_debugfs_client_cleanup(struct ceph_client *client)
+{
+}
+
+#endif  // CONFIG_DEBUG_FS
diff --git a/fs/ceph/decode.h b/fs/ceph/decode.h
new file mode 100644 (file)
index 0000000..65b3e02
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef __CEPH_DECODE_H
+#define __CEPH_DECODE_H
+
+#include <asm/unaligned.h>
+#include <linux/time.h>
+
+#include "types.h"
+
+/*
+ * in all cases,
+ *   void **p     pointer to position pointer
+ *   void *end    pointer to end of buffer (last byte + 1)
+ */
+
+static inline u64 ceph_decode_64(void **p)
+{
+       u64 v = get_unaligned_le64(*p);
+       *p += sizeof(u64);
+       return v;
+}
+static inline u32 ceph_decode_32(void **p)
+{
+       u32 v = get_unaligned_le32(*p);
+       *p += sizeof(u32);
+       return v;
+}
+static inline u16 ceph_decode_16(void **p)
+{
+       u16 v = get_unaligned_le16(*p);
+       *p += sizeof(u16);
+       return v;
+}
+static inline u8 ceph_decode_8(void **p)
+{
+       u8 v = *(u8 *)*p;
+       (*p)++;
+       return v;
+}
+static inline void ceph_decode_copy(void **p, void *pv, size_t n)
+{
+       memcpy(pv, *p, n);
+       *p += n;
+}
+
+/*
+ * bounds check input.
+ */
+#define ceph_decode_need(p, end, n, bad)               \
+       do {                                            \
+               if (unlikely(*(p) + (n) > (end)))       \
+                       goto bad;                       \
+       } while (0)
+
+#define ceph_decode_64_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_decode_need(p, end, sizeof(u64), bad);     \
+               v = ceph_decode_64(p);                          \
+       } while (0)
+#define ceph_decode_32_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_decode_need(p, end, sizeof(u32), bad);     \
+               v = ceph_decode_32(p);                          \
+       } while (0)
+#define ceph_decode_16_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_decode_need(p, end, sizeof(u16), bad);     \
+               v = ceph_decode_16(p);                          \
+       } while (0)
+#define ceph_decode_8_safe(p, end, v, bad)                     \
+       do {                                                    \
+               ceph_decode_need(p, end, sizeof(u8), bad);      \
+               v = ceph_decode_8(p);                           \
+       } while (0)
+
+#define ceph_decode_copy_safe(p, end, pv, n, bad)              \
+       do {                                                    \
+               ceph_decode_need(p, end, n, bad);               \
+               ceph_decode_copy(p, pv, n);                     \
+       } while (0)
+
+/*
+ * struct ceph_timespec <-> struct timespec
+ */
+static inline void ceph_decode_timespec(struct timespec *ts,
+                                       const struct ceph_timespec *tv)
+{
+       ts->tv_sec = le32_to_cpu(tv->tv_sec);
+       ts->tv_nsec = le32_to_cpu(tv->tv_nsec);
+}
+static inline void ceph_encode_timespec(struct ceph_timespec *tv,
+                                       const struct timespec *ts)
+{
+       tv->tv_sec = cpu_to_le32(ts->tv_sec);
+       tv->tv_nsec = cpu_to_le32(ts->tv_nsec);
+}
+
+/*
+ * sockaddr_storage <-> ceph_sockaddr
+ */
+static inline void ceph_encode_addr(struct ceph_entity_addr *a)
+{
+       a->in_addr.ss_family = htons(a->in_addr.ss_family);
+}
+static inline void ceph_decode_addr(struct ceph_entity_addr *a)
+{
+       a->in_addr.ss_family = ntohs(a->in_addr.ss_family);
+       WARN_ON(a->in_addr.ss_family == 512);
+}
+
+/*
+ * encoders
+ */
+static inline void ceph_encode_64(void **p, u64 v)
+{
+       put_unaligned_le64(v, (__le64 *)*p);
+       *p += sizeof(u64);
+}
+static inline void ceph_encode_32(void **p, u32 v)
+{
+       put_unaligned_le32(v, (__le32 *)*p);
+       *p += sizeof(u32);
+}
+static inline void ceph_encode_16(void **p, u16 v)
+{
+       put_unaligned_le16(v, (__le16 *)*p);
+       *p += sizeof(u16);
+}
+static inline void ceph_encode_8(void **p, u8 v)
+{
+       *(u8 *)*p = v;
+       (*p)++;
+}
+static inline void ceph_encode_copy(void **p, const void *s, int len)
+{
+       memcpy(*p, s, len);
+       *p += len;
+}
+
+/*
+ * filepath, string encoders
+ */
+static inline void ceph_encode_filepath(void **p, void *end,
+                                       u64 ino, const char *path)
+{
+       u32 len = path ? strlen(path) : 0;
+       BUG_ON(*p + sizeof(ino) + sizeof(len) + len > end);
+       ceph_encode_8(p, 1);
+       ceph_encode_64(p, ino);
+       ceph_encode_32(p, len);
+       if (len)
+               memcpy(*p, path, len);
+       *p += len;
+}
+
+static inline void ceph_encode_string(void **p, void *end,
+                                     const char *s, u32 len)
+{
+       BUG_ON(*p + sizeof(len) + len > end);
+       ceph_encode_32(p, len);
+       if (len)
+               memcpy(*p, s, len);
+       *p += len;
+}
+
+#define ceph_encode_need(p, end, n, bad)               \
+       do {                                            \
+               if (unlikely(*(p) + (n) > (end)))       \
+                       goto bad;                       \
+       } while (0)
+
+#define ceph_encode_64_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_encode_need(p, end, sizeof(u64), bad);     \
+               ceph_encode_64(p, v);                           \
+       } while (0)
+#define ceph_encode_32_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_encode_need(p, end, sizeof(u32), bad);     \
+               ceph_encode_32(p, v);                   \
+       } while (0)
+#define ceph_encode_16_safe(p, end, v, bad)                    \
+       do {                                                    \
+               ceph_encode_need(p, end, sizeof(u16), bad);     \
+               ceph_encode_16(p, v);                   \
+       } while (0)
+
+#define ceph_encode_copy_safe(p, end, pv, n, bad)              \
+       do {                                                    \
+               ceph_encode_need(p, end, n, bad);               \
+               ceph_encode_copy(p, pv, n);                     \
+       } while (0)
+
+
+#endif
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
new file mode 100644 (file)
index 0000000..5107384
--- /dev/null
@@ -0,0 +1,1220 @@
+#include "ceph_debug.h"
+
+#include <linux/spinlock.h>
+#include <linux/fs_struct.h>
+#include <linux/namei.h>
+#include <linux/sched.h>
+
+#include "super.h"
+
+/*
+ * Directory operations: readdir, lookup, create, link, unlink,
+ * rename, etc.
+ */
+
+/*
+ * Ceph MDS operations are specified in terms of a base ino and
+ * relative path.  Thus, the client can specify an operation on a
+ * specific inode (e.g., a getattr due to fstat(2)), or as a path
+ * relative to, say, the root directory.
+ *
+ * Normally, we limit ourselves to strict inode ops (no path component)
+ * or dentry operations (a single path component relative to an ino).  The
+ * exception to this is open_root_dentry(), which will open the mount
+ * point by name.
+ */
+
+const struct inode_operations ceph_dir_iops;
+const struct file_operations ceph_dir_fops;
+struct dentry_operations ceph_dentry_ops;
+
+/*
+ * Initialize ceph dentry state.
+ */
+int ceph_init_dentry(struct dentry *dentry)
+{
+       struct ceph_dentry_info *di;
+
+       if (dentry->d_fsdata)
+               return 0;
+
+       if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
+               dentry->d_op = &ceph_dentry_ops;
+       else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
+               dentry->d_op = &ceph_snapdir_dentry_ops;
+       else
+               dentry->d_op = &ceph_snap_dentry_ops;
+
+       di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS);
+       if (!di)
+               return -ENOMEM;          /* oh well */
+
+       spin_lock(&dentry->d_lock);
+       if (dentry->d_fsdata) /* lost a race */
+               goto out_unlock;
+       di->dentry = dentry;
+       di->lease_session = NULL;
+       dentry->d_fsdata = di;
+       dentry->d_time = jiffies;
+       ceph_dentry_lru_add(dentry);
+out_unlock:
+       spin_unlock(&dentry->d_lock);
+       return 0;
+}
+
+
+
+/*
+ * for readdir, we encode the directory frag and offset within that
+ * frag into f_pos.
+ */
+static unsigned fpos_frag(loff_t p)
+{
+       return p >> 32;
+}
+static unsigned fpos_off(loff_t p)
+{
+       return p & 0xffffffff;
+}
+
+/*
+ * When possible, we try to satisfy a readdir by peeking at the
+ * dcache.  We make this work by carefully ordering dentries on
+ * d_u.d_child when we initially get results back from the MDS, and
+ * falling back to a "normal" sync readdir if any dentries in the dir
+ * are dropped.
+ *
+ * I_COMPLETE tells indicates we have all dentries in the dir.  It is
+ * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
+ * the MDS if/when the directory is modified).
+ */
+static int __dcache_readdir(struct file *filp,
+                           void *dirent, filldir_t filldir)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct ceph_file_info *fi = filp->private_data;
+       struct dentry *parent = filp->f_dentry;
+       struct inode *dir = parent->d_inode;
+       struct list_head *p;
+       struct dentry *dentry, *last;
+       struct ceph_dentry_info *di;
+       int err = 0;
+
+       /* claim ref on last dentry we returned */
+       last = fi->dentry;
+       fi->dentry = NULL;
+
+       dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,
+            last);
+
+       spin_lock(&dcache_lock);
+
+       /* start at beginning? */
+       if (filp->f_pos == 2 || (last &&
+                                filp->f_pos < ceph_dentry(last)->offset)) {
+               if (list_empty(&parent->d_subdirs))
+                       goto out_unlock;
+               p = parent->d_subdirs.prev;
+               dout(" initial p %p/%p\n", p->prev, p->next);
+       } else {
+               p = last->d_u.d_child.prev;
+       }
+
+more:
+       dentry = list_entry(p, struct dentry, d_u.d_child);
+       di = ceph_dentry(dentry);
+       while (1) {
+               dout(" p %p/%p d_subdirs %p/%p\n", p->prev, p->next,
+                    parent->d_subdirs.prev, parent->d_subdirs.next);
+               if (p == &parent->d_subdirs) {
+                       fi->at_end = 1;
+                       goto out_unlock;
+               }
+               if (!d_unhashed(dentry) && dentry->d_inode &&
+                   ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
+                   ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
+                   filp->f_pos <= di->offset)
+                       break;
+               dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
+                    dentry->d_name.len, dentry->d_name.name, di->offset,
+                    filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
+                    !dentry->d_inode ? " null" : "");
+               p = p->prev;
+               dentry = list_entry(p, struct dentry, d_u.d_child);
+               di = ceph_dentry(dentry);
+       }
+
+       atomic_inc(&dentry->d_count);
+       spin_unlock(&dcache_lock);
+       spin_unlock(&inode->i_lock);
+
+       dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
+            dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+       filp->f_pos = di->offset;
+       err = filldir(dirent, dentry->d_name.name,
+                     dentry->d_name.len, di->offset,
+                     dentry->d_inode->i_ino,
+                     dentry->d_inode->i_mode >> 12);
+
+       if (last) {
+               if (err < 0) {
+                       /* remember our position */
+                       fi->dentry = last;
+                       fi->next_offset = di->offset;
+               } else {
+                       dput(last);
+               }
+               last = NULL;
+       }
+
+       spin_lock(&inode->i_lock);
+       spin_lock(&dcache_lock);
+
+       if (err < 0)
+               goto out_unlock;
+
+       last = dentry;
+
+       p = p->prev;
+       filp->f_pos++;
+
+       /* make sure a dentry wasn't dropped while we didn't have dcache_lock */
+       if ((ceph_inode(dir)->i_ceph_flags & CEPH_I_COMPLETE))
+               goto more;
+       dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
+       err = -EAGAIN;
+
+out_unlock:
+       spin_unlock(&dcache_lock);
+
+       if (last) {
+               spin_unlock(&inode->i_lock);
+               dput(last);
+               spin_lock(&inode->i_lock);
+       }
+
+       return err;
+}
+
+/*
+ * make note of the last dentry we read, so we can
+ * continue at the same lexicographical point,
+ * regardless of what dir changes take place on the
+ * server.
+ */
+static int note_last_dentry(struct ceph_file_info *fi, const char *name,
+                           int len)
+{
+       kfree(fi->last_name);
+       fi->last_name = kmalloc(len+1, GFP_NOFS);
+       if (!fi->last_name)
+               return -ENOMEM;
+       memcpy(fi->last_name, name, len);
+       fi->last_name[len] = 0;
+       dout("note_last_dentry '%s'\n", fi->last_name);
+       return 0;
+}
+
+static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct ceph_file_info *fi = filp->private_data;
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       unsigned frag = fpos_frag(filp->f_pos);
+       int off = fpos_off(filp->f_pos);
+       int err;
+       u32 ftype;
+       struct ceph_mds_reply_info_parsed *rinfo;
+       const int max_entries = client->mount_args->max_readdir;
+
+       dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
+       if (fi->at_end)
+               return 0;
+
+       /* always start with . and .. */
+       if (filp->f_pos == 0) {
+               /* note dir version at start of readdir so we can tell
+                * if any dentries get dropped */
+               fi->dir_release_count = ci->i_release_count;
+
+               dout("readdir off 0 -> '.'\n");
+               if (filldir(dirent, ".", 1, ceph_make_fpos(0, 0),
+                           inode->i_ino, inode->i_mode >> 12) < 0)
+                       return 0;
+               filp->f_pos = 1;
+               off = 1;
+       }
+       if (filp->f_pos == 1) {
+               dout("readdir off 1 -> '..'\n");
+               if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1),
+                           filp->f_dentry->d_parent->d_inode->i_ino,
+                           inode->i_mode >> 12) < 0)
+                       return 0;
+               filp->f_pos = 2;
+               off = 2;
+       }
+
+       /* can we use the dcache? */
+       spin_lock(&inode->i_lock);
+       if ((filp->f_pos == 2 || fi->dentry) &&
+           !ceph_test_opt(client, NOASYNCREADDIR) &&
+           (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
+           __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
+               err = __dcache_readdir(filp, dirent, filldir);
+               if (err != -EAGAIN) {
+                       spin_unlock(&inode->i_lock);
+                       return err;
+               }
+       }
+       spin_unlock(&inode->i_lock);
+       if (fi->dentry) {
+               err = note_last_dentry(fi, fi->dentry->d_name.name,
+                                      fi->dentry->d_name.len);
+               if (err)
+                       return err;
+               dput(fi->dentry);
+               fi->dentry = NULL;
+       }
+
+       /* proceed with a normal readdir */
+
+more:
+       /* do we have the correct frag content buffered? */
+       if (fi->frag != frag || fi->last_readdir == NULL) {
+               struct ceph_mds_request *req;
+               int op = ceph_snap(inode) == CEPH_SNAPDIR ?
+                       CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR;
+
+               /* discard old result, if any */
+               if (fi->last_readdir)
+                       ceph_mdsc_put_request(fi->last_readdir);
+
+               /* requery frag tree, as the frag topology may have changed */
+               frag = ceph_choose_frag(ceph_inode(inode), frag, NULL, NULL);
+
+               dout("readdir fetching %llx.%llx frag %x offset '%s'\n",
+                    ceph_vinop(inode), frag, fi->last_name);
+               req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+               if (IS_ERR(req))
+                       return PTR_ERR(req);
+               req->r_inode = igrab(inode);
+               req->r_dentry = dget(filp->f_dentry);
+               /* hints to request -> mds selection code */
+               req->r_direct_mode = USE_AUTH_MDS;
+               req->r_direct_hash = ceph_frag_value(frag);
+               req->r_direct_is_hash = true;
+               req->r_path2 = kstrdup(fi->last_name, GFP_NOFS);
+               req->r_readdir_offset = fi->next_offset;
+               req->r_args.readdir.frag = cpu_to_le32(frag);
+               req->r_args.readdir.max_entries = cpu_to_le32(max_entries);
+               req->r_num_caps = max_entries;
+               err = ceph_mdsc_do_request(mdsc, NULL, req);
+               if (err < 0) {
+                       ceph_mdsc_put_request(req);
+                       return err;
+               }
+               dout("readdir got and parsed readdir result=%d"
+                    " on frag %x, end=%d, complete=%d\n", err, frag,
+                    (int)req->r_reply_info.dir_end,
+                    (int)req->r_reply_info.dir_complete);
+
+               if (!req->r_did_prepopulate) {
+                       dout("readdir !did_prepopulate");
+                       fi->dir_release_count--;    /* preclude I_COMPLETE */
+               }
+
+               /* note next offset and last dentry name */
+               fi->offset = fi->next_offset;
+               fi->last_readdir = req;
+
+               if (req->r_reply_info.dir_end) {
+                       kfree(fi->last_name);
+                       fi->last_name = NULL;
+                       fi->next_offset = 0;
+               } else {
+                       rinfo = &req->r_reply_info;
+                       err = note_last_dentry(fi,
+                                      rinfo->dir_dname[rinfo->dir_nr-1],
+                                      rinfo->dir_dname_len[rinfo->dir_nr-1]);
+                       if (err)
+                               return err;
+                       fi->next_offset += rinfo->dir_nr;
+               }
+       }
+
+       rinfo = &fi->last_readdir->r_reply_info;
+       dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
+            rinfo->dir_nr, off, fi->offset);
+       while (off - fi->offset >= 0 && off - fi->offset < rinfo->dir_nr) {
+               u64 pos = ceph_make_fpos(frag, off);
+               struct ceph_mds_reply_inode *in =
+                       rinfo->dir_in[off - fi->offset].in;
+               dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
+                    off, off - fi->offset, rinfo->dir_nr, pos,
+                    rinfo->dir_dname_len[off - fi->offset],
+                    rinfo->dir_dname[off - fi->offset], in);
+               BUG_ON(!in);
+               ftype = le32_to_cpu(in->mode) >> 12;
+               if (filldir(dirent,
+                           rinfo->dir_dname[off - fi->offset],
+                           rinfo->dir_dname_len[off - fi->offset],
+                           pos,
+                           le64_to_cpu(in->ino),
+                           ftype) < 0) {
+                       dout("filldir stopping us...\n");
+                       return 0;
+               }
+               off++;
+               filp->f_pos = pos + 1;
+       }
+
+       if (fi->last_name) {
+               ceph_mdsc_put_request(fi->last_readdir);
+               fi->last_readdir = NULL;
+               goto more;
+       }
+
+       /* more frags? */
+       if (!ceph_frag_is_rightmost(frag)) {
+               frag = ceph_frag_next(frag);
+               off = 0;
+               filp->f_pos = ceph_make_fpos(frag, off);
+               dout("readdir next frag is %x\n", frag);
+               goto more;
+       }
+       fi->at_end = 1;
+
+       /*
+        * if dir_release_count still matches the dir, no dentries
+        * were released during the whole readdir, and we should have
+        * the complete dir contents in our cache.
+        */
+       spin_lock(&inode->i_lock);
+       if (ci->i_release_count == fi->dir_release_count) {
+               dout(" marking %p complete\n", inode);
+               ci->i_ceph_flags |= CEPH_I_COMPLETE;
+               ci->i_max_offset = filp->f_pos;
+       }
+       spin_unlock(&inode->i_lock);
+
+       dout("readdir %p filp %p done.\n", inode, filp);
+       return 0;
+}
+
+static void reset_readdir(struct ceph_file_info *fi)
+{
+       if (fi->last_readdir) {
+               ceph_mdsc_put_request(fi->last_readdir);
+               fi->last_readdir = NULL;
+       }
+       kfree(fi->last_name);
+       fi->next_offset = 2;  /* compensate for . and .. */
+       if (fi->dentry) {
+               dput(fi->dentry);
+               fi->dentry = NULL;
+       }
+       fi->at_end = 0;
+}
+
+static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+       struct ceph_file_info *fi = file->private_data;
+       struct inode *inode = file->f_mapping->host;
+       loff_t old_offset = offset;
+       loff_t retval;
+
+       mutex_lock(&inode->i_mutex);
+       switch (origin) {
+       case SEEK_END:
+               offset += inode->i_size + 2;   /* FIXME */
+               break;
+       case SEEK_CUR:
+               offset += file->f_pos;
+       }
+       retval = -EINVAL;
+       if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+               if (offset != file->f_pos) {
+                       file->f_pos = offset;
+                       file->f_version = 0;
+                       fi->at_end = 0;
+               }
+               retval = offset;
+
+               /*
+                * discard buffered readdir content on seekdir(0), or
+                * seek to new frag, or seek prior to current chunk.
+                */
+               if (offset == 0 ||
+                   fpos_frag(offset) != fpos_frag(old_offset) ||
+                   fpos_off(offset) < fi->offset) {
+                       dout("dir_llseek dropping %p content\n", file);
+                       reset_readdir(fi);
+               }
+
+               /* bump dir_release_count if we did a forward seek */
+               if (offset > old_offset)
+                       fi->dir_release_count--;
+       }
+       mutex_unlock(&inode->i_mutex);
+       return retval;
+}
+
+/*
+ * Process result of a lookup/open request.
+ *
+ * Mainly, make sure we return the final req->r_dentry (if it already
+ * existed) in place of the original VFS-provided dentry when they
+ * differ.
+ *
+ * Gracefully handle the case where the MDS replies with -ENOENT and
+ * no trace (which it may do, at its discretion, e.g., if it doesn't
+ * care to issue a lease on the negative dentry).
+ */
+struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
+                                 struct dentry *dentry, int err)
+{
+       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct inode *parent = dentry->d_parent->d_inode;
+
+       /* .snap dir? */
+       if (err == -ENOENT &&
+           ceph_vino(parent).ino != CEPH_INO_ROOT && /* no .snap in root dir */
+           strcmp(dentry->d_name.name,
+                  client->mount_args->snapdir_name) == 0) {
+               struct inode *inode = ceph_get_snapdir(parent);
+               dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
+                    dentry, dentry->d_name.len, dentry->d_name.name, inode);
+               d_add(dentry, inode);
+               err = 0;
+       }
+
+       if (err == -ENOENT) {
+               /* no trace? */
+               err = 0;
+               if (!req->r_reply_info.head->is_dentry) {
+                       dout("ENOENT and no trace, dentry %p inode %p\n",
+                            dentry, dentry->d_inode);
+                       if (dentry->d_inode) {
+                               d_drop(dentry);
+                               err = -ENOENT;
+                       } else {
+                               d_add(dentry, NULL);
+                       }
+               }
+       }
+       if (err)
+               dentry = ERR_PTR(err);
+       else if (dentry != req->r_dentry)
+               dentry = dget(req->r_dentry);   /* we got spliced */
+       else
+               dentry = NULL;
+       return dentry;
+}
+
+static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
+{
+       return ceph_ino(inode) == CEPH_INO_ROOT &&
+               strncmp(dentry->d_name.name, ".ceph", 5) == 0;
+}
+
+/*
+ * Look up a single dir entry.  If there is a lookup intent, inform
+ * the MDS so that it gets our 'caps wanted' value in a single op.
+ */
+static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
+                                 struct nameidata *nd)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int op;
+       int err;
+
+       dout("lookup %p dentry %p '%.*s'\n",
+            dir, dentry, dentry->d_name.len, dentry->d_name.name);
+
+       if (dentry->d_name.len > NAME_MAX)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       err = ceph_init_dentry(dentry);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       /* open (but not create!) intent? */
+       if (nd &&
+           (nd->flags & LOOKUP_OPEN) &&
+           (nd->flags & LOOKUP_CONTINUE) == 0 && /* only open last component */
+           !(nd->intent.open.flags & O_CREAT)) {
+               int mode = nd->intent.open.create_mode & ~current->fs->umask;
+               return ceph_lookup_open(dir, dentry, nd, mode, 1);
+       }
+
+       /* can we conclude ENOENT locally? */
+       if (dentry->d_inode == NULL) {
+               struct ceph_inode_info *ci = ceph_inode(dir);
+               struct ceph_dentry_info *di = ceph_dentry(dentry);
+
+               spin_lock(&dir->i_lock);
+               dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
+               if (strncmp(dentry->d_name.name,
+                           client->mount_args->snapdir_name,
+                           dentry->d_name.len) &&
+                   !is_root_ceph_dentry(dir, dentry) &&
+                   (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
+                   (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
+                       di->offset = ci->i_max_offset++;
+                       spin_unlock(&dir->i_lock);
+                       dout(" dir %p complete, -ENOENT\n", dir);
+                       d_add(dentry, NULL);
+                       di->lease_shared_gen = ci->i_shared_gen;
+                       return NULL;
+               }
+               spin_unlock(&dir->i_lock);
+       }
+
+       op = ceph_snap(dir) == CEPH_SNAPDIR ?
+               CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
+       req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
+       if (IS_ERR(req))
+               return ERR_PTR(PTR_ERR(req));
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       /* we only need inode linkage */
+       req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
+       req->r_locked_dir = dir;
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+       dentry = ceph_finish_lookup(req, dentry, err);
+       ceph_mdsc_put_request(req);  /* will dput(dentry) */
+       dout("lookup result=%p\n", dentry);
+       return dentry;
+}
+
+/*
+ * If we do a create but get no trace back from the MDS, follow up with
+ * a lookup (the VFS expects us to link up the provided dentry).
+ */
+int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *result = ceph_lookup(dir, dentry, NULL);
+
+       if (result && !IS_ERR(result)) {
+               /*
+                * We created the item, then did a lookup, and found
+                * it was already linked to another inode we already
+                * had in our cache (and thus got spliced).  Link our
+                * dentry to that inode, but don't hash it, just in
+                * case the VFS wants to dereference it.
+                */
+               BUG_ON(!result->d_inode);
+               d_instantiate(dentry, result->d_inode);
+               return 0;
+       }
+       return PTR_ERR(result);
+}
+
+static int ceph_mknod(struct inode *dir, struct dentry *dentry,
+                     int mode, dev_t rdev)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err;
+
+       if (ceph_snap(dir) != CEPH_NOSNAP)
+               return -EROFS;
+
+       dout("mknod in dir %p dentry %p mode 0%o rdev %d\n",
+            dir, dentry, mode, rdev);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKNOD, USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               d_drop(dentry);
+               return PTR_ERR(req);
+       }
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       req->r_locked_dir = dir;
+       req->r_args.mknod.mode = cpu_to_le32(mode);
+       req->r_args.mknod.rdev = cpu_to_le32(rdev);
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       err = ceph_mdsc_do_request(mdsc, dir, req);
+       if (!err && !req->r_reply_info.head->is_dentry)
+               err = ceph_handle_notrace_create(dir, dentry);
+       ceph_mdsc_put_request(req);
+       if (err)
+               d_drop(dentry);
+       return err;
+}
+
+static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
+                      struct nameidata *nd)
+{
+       dout("create in dir %p dentry %p name '%.*s'\n",
+            dir, dentry, dentry->d_name.len, dentry->d_name.name);
+
+       if (ceph_snap(dir) != CEPH_NOSNAP)
+               return -EROFS;
+
+       if (nd) {
+               BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
+               dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
+               /* hrm, what should i do here if we get aliased? */
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+               return 0;
+       }
+
+       /* fall back to mknod */
+       return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0);
+}
+
+static int ceph_symlink(struct inode *dir, struct dentry *dentry,
+                           const char *dest)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err;
+
+       if (ceph_snap(dir) != CEPH_NOSNAP)
+               return -EROFS;
+
+       dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               d_drop(dentry);
+               return PTR_ERR(req);
+       }
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       req->r_path2 = kstrdup(dest, GFP_NOFS);
+       req->r_locked_dir = dir;
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       err = ceph_mdsc_do_request(mdsc, dir, req);
+       if (!err && !req->r_reply_info.head->is_dentry)
+               err = ceph_handle_notrace_create(dir, dentry);
+       ceph_mdsc_put_request(req);
+       if (err)
+               d_drop(dentry);
+       return err;
+}
+
+static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err = -EROFS;
+       int op;
+
+       if (ceph_snap(dir) == CEPH_SNAPDIR) {
+               /* mkdir .snap/foo is a MKSNAP */
+               op = CEPH_MDS_OP_MKSNAP;
+               dout("mksnap dir %p snap '%.*s' dn %p\n", dir,
+                    dentry->d_name.len, dentry->d_name.name, dentry);
+       } else if (ceph_snap(dir) == CEPH_NOSNAP) {
+               dout("mkdir dir %p dn %p mode 0%o\n", dir, dentry, mode);
+               op = CEPH_MDS_OP_MKDIR;
+       } else {
+               goto out;
+       }
+       req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto out;
+       }
+
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       req->r_locked_dir = dir;
+       req->r_args.mkdir.mode = cpu_to_le32(mode);
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       err = ceph_mdsc_do_request(mdsc, dir, req);
+       if (!err && !req->r_reply_info.head->is_dentry)
+               err = ceph_handle_notrace_create(dir, dentry);
+       ceph_mdsc_put_request(req);
+out:
+       if (err < 0)
+               d_drop(dentry);
+       return err;
+}
+
+static int ceph_link(struct dentry *old_dentry, struct inode *dir,
+                    struct dentry *dentry)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err;
+
+       if (ceph_snap(dir) != CEPH_NOSNAP)
+               return -EROFS;
+
+       dout("link in dir %p old_dentry %p dentry %p\n", dir,
+            old_dentry, dentry);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               d_drop(dentry);
+               return PTR_ERR(req);
+       }
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
+       req->r_locked_dir = dir;
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       err = ceph_mdsc_do_request(mdsc, dir, req);
+       if (err)
+               d_drop(dentry);
+       else if (!req->r_reply_info.head->is_dentry)
+               d_instantiate(dentry, igrab(old_dentry->d_inode));
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
+/*
+ * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps.  If it
+ * looks like the link count will hit 0, drop any other caps (other
+ * than PIN) we don't specifically want (due to the file still being
+ * open).
+ */
+static int drop_caps_for_unlink(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
+
+       spin_lock(&inode->i_lock);
+       if (inode->i_nlink == 1) {
+               drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
+               ci->i_ceph_flags |= CEPH_I_NODELAY;
+       }
+       spin_unlock(&inode->i_lock);
+       return drop;
+}
+
+/*
+ * rmdir and unlink are differ only by the metadata op code
+ */
+static int ceph_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct inode *inode = dentry->d_inode;
+       struct ceph_mds_request *req;
+       int err = -EROFS;
+       int op;
+
+       if (ceph_snap(dir) == CEPH_SNAPDIR) {
+               /* rmdir .snap/foo is RMSNAP */
+               dout("rmsnap dir %p '%.*s' dn %p\n", dir, dentry->d_name.len,
+                    dentry->d_name.name, dentry);
+               op = CEPH_MDS_OP_RMSNAP;
+       } else if (ceph_snap(dir) == CEPH_NOSNAP) {
+               dout("unlink/rmdir dir %p dn %p inode %p\n",
+                    dir, dentry, inode);
+               op = ((dentry->d_inode->i_mode & S_IFMT) == S_IFDIR) ?
+                       CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK;
+       } else
+               goto out;
+       req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto out;
+       }
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       req->r_locked_dir = dir;
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       req->r_inode_drop = drop_caps_for_unlink(inode);
+       err = ceph_mdsc_do_request(mdsc, dir, req);
+       if (!err && !req->r_reply_info.head->is_dentry)
+               d_delete(dentry);
+       ceph_mdsc_put_request(req);
+out:
+       return err;
+}
+
+static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
+                      struct inode *new_dir, struct dentry *new_dentry)
+{
+       struct ceph_client *client = ceph_sb_to_client(old_dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err;
+
+       if (ceph_snap(old_dir) != ceph_snap(new_dir))
+               return -EXDEV;
+       if (ceph_snap(old_dir) != CEPH_NOSNAP ||
+           ceph_snap(new_dir) != CEPH_NOSNAP)
+               return -EROFS;
+       dout("rename dir %p dentry %p to dir %p dentry %p\n",
+            old_dir, old_dentry, new_dir, new_dentry);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RENAME, USE_AUTH_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       req->r_dentry = dget(new_dentry);
+       req->r_num_caps = 2;
+       req->r_old_dentry = dget(old_dentry);
+       req->r_locked_dir = new_dir;
+       req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
+       req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+       req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       /* release LINK_RDCACHE on source inode (mds will lock it) */
+       req->r_old_inode_drop = CEPH_CAP_LINK_SHARED;
+       if (new_dentry->d_inode)
+               req->r_inode_drop = drop_caps_for_unlink(new_dentry->d_inode);
+       err = ceph_mdsc_do_request(mdsc, old_dir, req);
+       if (!err && !req->r_reply_info.head->is_dentry) {
+               /*
+                * Normally d_move() is done by fill_trace (called by
+                * do_request, above).  If there is no trace, we need
+                * to do it here.
+                */
+               d_move(old_dentry, new_dentry);
+       }
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
+
+/*
+ * Check if dentry lease is valid.  If not, delete the lease.  Try to
+ * renew if the least is more than half up.
+ */
+static int dentry_lease_is_valid(struct dentry *dentry)
+{
+       struct ceph_dentry_info *di;
+       struct ceph_mds_session *s;
+       int valid = 0;
+       u32 gen;
+       unsigned long ttl;
+       struct ceph_mds_session *session = NULL;
+       struct inode *dir = NULL;
+       u32 seq = 0;
+
+       spin_lock(&dentry->d_lock);
+       di = ceph_dentry(dentry);
+       if (di && di->lease_session) {
+               s = di->lease_session;
+               spin_lock(&s->s_cap_lock);
+               gen = s->s_cap_gen;
+               ttl = s->s_cap_ttl;
+               spin_unlock(&s->s_cap_lock);
+
+               if (di->lease_gen == gen &&
+                   time_before(jiffies, dentry->d_time) &&
+                   time_before(jiffies, ttl)) {
+                       valid = 1;
+                       if (di->lease_renew_after &&
+                           time_after(jiffies, di->lease_renew_after)) {
+                               /* we should renew */
+                               dir = dentry->d_parent->d_inode;
+                               session = ceph_get_mds_session(s);
+                               seq = di->lease_seq;
+                               di->lease_renew_after = 0;
+                               di->lease_renew_from = jiffies;
+                       }
+               }
+       }
+       spin_unlock(&dentry->d_lock);
+
+       if (session) {
+               ceph_mdsc_lease_send_msg(session, dir, dentry,
+                                        CEPH_MDS_LEASE_RENEW, seq);
+               ceph_put_mds_session(session);
+       }
+       dout("dentry_lease_is_valid - dentry %p = %d\n", dentry, valid);
+       return valid;
+}
+
+/*
+ * Check if directory-wide content lease/cap is valid.
+ */
+static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
+{
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+       int valid = 0;
+
+       spin_lock(&dir->i_lock);
+       if (ci->i_shared_gen == di->lease_shared_gen)
+               valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+       spin_unlock(&dir->i_lock);
+       dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
+            dir, (unsigned)ci->i_shared_gen, dentry,
+            (unsigned)di->lease_shared_gen, valid);
+       return valid;
+}
+
+/*
+ * Check if cached dentry can be trusted.
+ */
+static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+
+       dout("d_revalidate %p '%.*s' inode %p\n", dentry,
+            dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+
+       /* always trust cached snapped dentries, snapdir dentry */
+       if (ceph_snap(dir) != CEPH_NOSNAP) {
+               dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry,
+                    dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+               goto out_touch;
+       }
+       if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR)
+               goto out_touch;
+
+       if (dentry_lease_is_valid(dentry) ||
+           dir_lease_is_valid(dir, dentry))
+               goto out_touch;
+
+       dout("d_revalidate %p invalid\n", dentry);
+       d_drop(dentry);
+       return 0;
+out_touch:
+       ceph_dentry_lru_touch(dentry);
+       return 1;
+}
+
+/*
+ * When a dentry is released, clear the dir I_COMPLETE if it was part
+ * of the current dir gen.
+ */
+static void ceph_dentry_release(struct dentry *dentry)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+       struct inode *parent_inode = dentry->d_parent->d_inode;
+
+       if (parent_inode) {
+               struct ceph_inode_info *ci = ceph_inode(parent_inode);
+
+               spin_lock(&parent_inode->i_lock);
+               if (ci->i_shared_gen == di->lease_shared_gen) {
+                       dout(" clearing %p complete (d_release)\n",
+                            parent_inode);
+                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+                       ci->i_release_count++;
+               }
+               spin_unlock(&parent_inode->i_lock);
+       }
+       if (di) {
+               ceph_dentry_lru_del(dentry);
+               if (di->lease_session)
+                       ceph_put_mds_session(di->lease_session);
+               kmem_cache_free(ceph_dentry_cachep, di);
+               dentry->d_fsdata = NULL;
+       }
+}
+
+static int ceph_snapdir_d_revalidate(struct dentry *dentry,
+                                         struct nameidata *nd)
+{
+       /*
+        * Eventually, we'll want to revalidate snapped metadata
+        * too... probably...
+        */
+       return 1;
+}
+
+
+
+/*
+ * read() on a dir.  This weird interface hack only works if mounted
+ * with '-o dirstat'.
+ */
+static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
+                            loff_t *ppos)
+{
+       struct ceph_file_info *cf = file->private_data;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int left;
+
+       if (!ceph_test_opt(ceph_client(inode->i_sb), DIRSTAT))
+               return -EISDIR;
+
+       if (!cf->dir_info) {
+               cf->dir_info = kmalloc(1024, GFP_NOFS);
+               if (!cf->dir_info)
+                       return -ENOMEM;
+               cf->dir_info_len =
+                       sprintf(cf->dir_info,
+                               "entries:   %20lld\n"
+                               " files:    %20lld\n"
+                               " subdirs:  %20lld\n"
+                               "rentries:  %20lld\n"
+                               " rfiles:   %20lld\n"
+                               " rsubdirs: %20lld\n"
+                               "rbytes:    %20lld\n"
+                               "rctime:    %10ld.%09ld\n",
+                               ci->i_files + ci->i_subdirs,
+                               ci->i_files,
+                               ci->i_subdirs,
+                               ci->i_rfiles + ci->i_rsubdirs,
+                               ci->i_rfiles,
+                               ci->i_rsubdirs,
+                               ci->i_rbytes,
+                               (long)ci->i_rctime.tv_sec,
+                               (long)ci->i_rctime.tv_nsec);
+       }
+
+       if (*ppos >= cf->dir_info_len)
+               return 0;
+       size = min_t(unsigned, size, cf->dir_info_len-*ppos);
+       left = copy_to_user(buf, cf->dir_info + *ppos, size);
+       if (left == size)
+               return -EFAULT;
+       *ppos += (size - left);
+       return size - left;
+}
+
+/*
+ * an fsync() on a dir will wait for any uncommitted directory
+ * operations to commit.
+ */
+static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
+                         int datasync)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct list_head *head = &ci->i_unsafe_dirops;
+       struct ceph_mds_request *req;
+       u64 last_tid;
+       int ret = 0;
+
+       dout("dir_fsync %p\n", inode);
+       spin_lock(&ci->i_unsafe_lock);
+       if (list_empty(head))
+               goto out;
+
+       req = list_entry(head->prev,
+                        struct ceph_mds_request, r_unsafe_dir_item);
+       last_tid = req->r_tid;
+
+       do {
+               ceph_mdsc_get_request(req);
+               spin_unlock(&ci->i_unsafe_lock);
+               dout("dir_fsync %p wait on tid %llu (until %llu)\n",
+                    inode, req->r_tid, last_tid);
+               if (req->r_timeout) {
+                       ret = wait_for_completion_timeout(
+                               &req->r_safe_completion, req->r_timeout);
+                       if (ret > 0)
+                               ret = 0;
+                       else if (ret == 0)
+                               ret = -EIO;  /* timed out */
+               } else {
+                       wait_for_completion(&req->r_safe_completion);
+               }
+               spin_lock(&ci->i_unsafe_lock);
+               ceph_mdsc_put_request(req);
+
+               if (ret || list_empty(head))
+                       break;
+               req = list_entry(head->next,
+                                struct ceph_mds_request, r_unsafe_dir_item);
+       } while (req->r_tid < last_tid);
+out:
+       spin_unlock(&ci->i_unsafe_lock);
+       return ret;
+}
+
+/*
+ * We maintain a private dentry LRU.
+ *
+ * FIXME: this needs to be changed to a per-mds lru to be useful.
+ */
+void ceph_dentry_lru_add(struct dentry *dn)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dn);
+       struct ceph_mds_client *mdsc;
+
+       dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
+            dn->d_name.len, dn->d_name.name);
+       if (di) {
+               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               spin_lock(&mdsc->dentry_lru_lock);
+               list_add_tail(&di->lru, &mdsc->dentry_lru);
+               mdsc->num_dentry++;
+               spin_unlock(&mdsc->dentry_lru_lock);
+       }
+}
+
+void ceph_dentry_lru_touch(struct dentry *dn)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dn);
+       struct ceph_mds_client *mdsc;
+
+       dout("dentry_lru_touch %p %p '%.*s'\n", di, dn,
+            dn->d_name.len, dn->d_name.name);
+       if (di) {
+               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               spin_lock(&mdsc->dentry_lru_lock);
+               list_move_tail(&di->lru, &mdsc->dentry_lru);
+               spin_unlock(&mdsc->dentry_lru_lock);
+       }
+}
+
+void ceph_dentry_lru_del(struct dentry *dn)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dn);
+       struct ceph_mds_client *mdsc;
+
+       dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
+            dn->d_name.len, dn->d_name.name);
+       if (di) {
+               mdsc = &ceph_client(dn->d_sb)->mdsc;
+               spin_lock(&mdsc->dentry_lru_lock);
+               list_del_init(&di->lru);
+               mdsc->num_dentry--;
+               spin_unlock(&mdsc->dentry_lru_lock);
+       }
+}
+
+const struct file_operations ceph_dir_fops = {
+       .read = ceph_read_dir,
+       .readdir = ceph_readdir,
+       .llseek = ceph_dir_llseek,
+       .open = ceph_open,
+       .release = ceph_release,
+       .unlocked_ioctl = ceph_ioctl,
+       .fsync = ceph_dir_fsync,
+};
+
+const struct inode_operations ceph_dir_iops = {
+       .lookup = ceph_lookup,
+       .permission = ceph_permission,
+       .getattr = ceph_getattr,
+       .setattr = ceph_setattr,
+       .setxattr = ceph_setxattr,
+       .getxattr = ceph_getxattr,
+       .listxattr = ceph_listxattr,
+       .removexattr = ceph_removexattr,
+       .mknod = ceph_mknod,
+       .symlink = ceph_symlink,
+       .mkdir = ceph_mkdir,
+       .link = ceph_link,
+       .unlink = ceph_unlink,
+       .rmdir = ceph_unlink,
+       .rename = ceph_rename,
+       .create = ceph_create,
+};
+
+struct dentry_operations ceph_dentry_ops = {
+       .d_revalidate = ceph_d_revalidate,
+       .d_release = ceph_dentry_release,
+};
+
+struct dentry_operations ceph_snapdir_dentry_ops = {
+       .d_revalidate = ceph_snapdir_d_revalidate,
+};
+
+struct dentry_operations ceph_snap_dentry_ops = {
+};
diff --git a/fs/ceph/export.c b/fs/ceph/export.c
new file mode 100644 (file)
index 0000000..fc68e39
--- /dev/null
@@ -0,0 +1,223 @@
+#include "ceph_debug.h"
+
+#include <linux/exportfs.h>
+#include <asm/unaligned.h>
+
+#include "super.h"
+
+/*
+ * NFS export support
+ *
+ * NFS re-export of a ceph mount is, at present, only semireliable.
+ * The basic issue is that the Ceph architectures doesn't lend itself
+ * well to generating filehandles that will remain valid forever.
+ *
+ * So, we do our best.  If you're lucky, your inode will be in the
+ * client's cache.  If it's not, and you have a connectable fh, then
+ * the MDS server may be able to find it for you.  Otherwise, you get
+ * ESTALE.
+ *
+ * There are ways to this more reliable, but in the non-connectable fh
+ * case, we won't every work perfectly, and in the connectable case,
+ * some changes are needed on the MDS side to work better.
+ */
+
+/*
+ * Basic fh
+ */
+struct ceph_nfs_fh {
+       u64 ino;
+} __attribute__ ((packed));
+
+/*
+ * Larger 'connectable' fh that includes parent ino and name hash.
+ * Use this whenever possible, as it works more reliably.
+ */
+struct ceph_nfs_confh {
+       u64 ino, parent_ino;
+       u32 parent_name_hash;
+} __attribute__ ((packed));
+
+static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
+                         int connectable)
+{
+       struct ceph_nfs_fh *fh = (void *)rawfh;
+       struct ceph_nfs_confh *cfh = (void *)rawfh;
+       struct dentry *parent = dentry->d_parent;
+       struct inode *inode = dentry->d_inode;
+       int type;
+
+       /* don't re-export snaps */
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return -EINVAL;
+
+       if (*max_len >= sizeof(*cfh)) {
+               dout("encode_fh %p connectable\n", dentry);
+               cfh->ino = ceph_ino(dentry->d_inode);
+               cfh->parent_ino = ceph_ino(parent->d_inode);
+               cfh->parent_name_hash = parent->d_name.hash;
+               *max_len = sizeof(*cfh);
+               type = 2;
+       } else if (*max_len > sizeof(*fh)) {
+               if (connectable)
+                       return -ENOSPC;
+               dout("encode_fh %p\n", dentry);
+               fh->ino = ceph_ino(dentry->d_inode);
+               *max_len = sizeof(*fh);
+               type = 1;
+       } else {
+               return -ENOSPC;
+       }
+       return type;
+}
+
+/*
+ * convert regular fh to dentry
+ *
+ * FIXME: we should try harder by querying the mds for the ino.
+ */
+static struct dentry *__fh_to_dentry(struct super_block *sb,
+                                    struct ceph_nfs_fh *fh)
+{
+       struct inode *inode;
+       struct dentry *dentry;
+       struct ceph_vino vino;
+       int err;
+
+       dout("__fh_to_dentry %llx\n", fh->ino);
+       vino.ino = fh->ino;
+       vino.snap = CEPH_NOSNAP;
+       inode = ceph_find_inode(sb, vino);
+       if (!inode)
+               return ERR_PTR(-ESTALE);
+
+       dentry = d_obtain_alias(inode);
+       if (!dentry) {
+               pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
+                      fh->ino, inode);
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       err = ceph_init_dentry(dentry);
+
+       if (err < 0) {
+               iput(inode);
+               return ERR_PTR(err);
+       }
+       dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
+       return dentry;
+}
+
+/*
+ * convert connectable fh to dentry
+ */
+static struct dentry *__cfh_to_dentry(struct super_block *sb,
+                                     struct ceph_nfs_confh *cfh)
+{
+       struct ceph_mds_client *mdsc = &ceph_client(sb)->mdsc;
+       struct inode *inode;
+       struct dentry *dentry;
+       struct ceph_vino vino;
+       int err;
+
+       dout("__cfh_to_dentry %llx (%llx/%x)\n",
+            cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
+
+       vino.ino = cfh->ino;
+       vino.snap = CEPH_NOSNAP;
+       inode = ceph_find_inode(sb, vino);
+       if (!inode) {
+               struct ceph_mds_request *req;
+
+               req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
+                                              USE_ANY_MDS);
+               if (IS_ERR(req))
+                       return ERR_PTR(PTR_ERR(req));
+
+               req->r_ino1 = vino;
+               req->r_ino2.ino = cfh->parent_ino;
+               req->r_ino2.snap = CEPH_NOSNAP;
+               req->r_path2 = kmalloc(16, GFP_NOFS);
+               snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
+               req->r_num_caps = 1;
+               err = ceph_mdsc_do_request(mdsc, NULL, req);
+               ceph_mdsc_put_request(req);
+               inode = ceph_find_inode(sb, vino);
+               if (!inode)
+                       return ERR_PTR(err ? err : -ESTALE);
+       }
+
+       dentry = d_obtain_alias(inode);
+       if (!dentry) {
+               pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
+                      cfh->ino, inode);
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       err = ceph_init_dentry(dentry);
+       if (err < 0) {
+               iput(inode);
+               return ERR_PTR(err);
+       }
+       dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
+       return dentry;
+}
+
+static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
+                                       int fh_len, int fh_type)
+{
+       if (fh_type == 1)
+               return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
+       else
+               return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
+}
+
+/*
+ * get parent, if possible.
+ *
+ * FIXME: we could do better by querying the mds to discover the
+ * parent.
+ */
+static struct dentry *ceph_fh_to_parent(struct super_block *sb,
+                                        struct fid *fid,
+                                       int fh_len, int fh_type)
+{
+       struct ceph_nfs_confh *cfh = (void *)fid->raw;
+       struct ceph_vino vino;
+       struct inode *inode;
+       struct dentry *dentry;
+       int err;
+
+       if (fh_type == 1)
+               return ERR_PTR(-ESTALE);
+
+       pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
+                cfh->parent_name_hash);
+
+       vino.ino = cfh->ino;
+       vino.snap = CEPH_NOSNAP;
+       inode = ceph_find_inode(sb, vino);
+       if (!inode)
+               return ERR_PTR(-ESTALE);
+
+       dentry = d_obtain_alias(inode);
+       if (!dentry) {
+               pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
+                      cfh->ino, inode);
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       err = ceph_init_dentry(dentry);
+       if (err < 0) {
+               iput(inode);
+               return ERR_PTR(err);
+       }
+       dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
+       return dentry;
+}
+
+const struct export_operations ceph_export_ops = {
+       .encode_fh = ceph_encode_fh,
+       .fh_to_dentry = ceph_fh_to_dentry,
+       .fh_to_parent = ceph_fh_to_parent,
+};
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
new file mode 100644 (file)
index 0000000..5d2af84
--- /dev/null
@@ -0,0 +1,937 @@
+#include "ceph_debug.h"
+
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/writeback.h>
+
+#include "super.h"
+#include "mds_client.h"
+
+/*
+ * Ceph file operations
+ *
+ * Implement basic open/close functionality, and implement
+ * read/write.
+ *
+ * We implement three modes of file I/O:
+ *  - buffered uses the generic_file_aio_{read,write} helpers
+ *
+ *  - synchronous is used when there is multi-client read/write
+ *    sharing, avoids the page cache, and synchronously waits for an
+ *    ack from the OSD.
+ *
+ *  - direct io takes the variant of the sync path that references
+ *    user pages directly.
+ *
+ * fsync() flushes and waits on dirty pages, but just queues metadata
+ * for writeback: since the MDS can recover size and mtime there is no
+ * need to wait for MDS acknowledgement.
+ */
+
+
+/*
+ * Prepare an open request.  Preallocate ceph_cap to avoid an
+ * inopportune ENOMEM later.
+ */
+static struct ceph_mds_request *
+prepare_open_request(struct super_block *sb, int flags, int create_mode)
+{
+       struct ceph_client *client = ceph_sb_to_client(sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int want_auth = USE_ANY_MDS;
+       int op = (flags & O_CREAT) ? CEPH_MDS_OP_CREATE : CEPH_MDS_OP_OPEN;
+
+       if (flags & (O_WRONLY|O_RDWR|O_CREAT|O_TRUNC))
+               want_auth = USE_AUTH_MDS;
+
+       req = ceph_mdsc_create_request(mdsc, op, want_auth);
+       if (IS_ERR(req))
+               goto out;
+       req->r_fmode = ceph_flags_to_mode(flags);
+       req->r_args.open.flags = cpu_to_le32(flags);
+       req->r_args.open.mode = cpu_to_le32(create_mode);
+       req->r_args.open.preferred = cpu_to_le32(-1);
+out:
+       return req;
+}
+
+/*
+ * initialize private struct file data.
+ * if we fail, clean up by dropping fmode reference on the ceph_inode
+ */
+static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
+{
+       struct ceph_file_info *cf;
+       int ret = 0;
+
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFREG:
+       case S_IFDIR:
+               dout("init_file %p %p 0%o (regular)\n", inode, file,
+                    inode->i_mode);
+               cf = kmem_cache_alloc(ceph_file_cachep, GFP_NOFS | __GFP_ZERO);
+               if (cf == NULL) {
+                       ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+                       return -ENOMEM;
+               }
+               cf->fmode = fmode;
+               cf->next_offset = 2;
+               file->private_data = cf;
+               BUG_ON(inode->i_fop->release != ceph_release);
+               break;
+
+       case S_IFLNK:
+               dout("init_file %p %p 0%o (symlink)\n", inode, file,
+                    inode->i_mode);
+               ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+               break;
+
+       default:
+               dout("init_file %p %p 0%o (special)\n", inode, file,
+                    inode->i_mode);
+               /*
+                * we need to drop the open ref now, since we don't
+                * have .release set to ceph_release.
+                */
+               ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+               BUG_ON(inode->i_fop->release == ceph_release);
+
+               /* call the proper open fop */
+               ret = inode->i_fop->open(inode, file);
+       }
+       return ret;
+}
+
+/*
+ * If the filp already has private_data, that means the file was
+ * already opened by intent during lookup, and we do nothing.
+ *
+ * If we already have the requisite capabilities, we can satisfy
+ * the open request locally (no need to request new caps from the
+ * MDS).  We do, however, need to inform the MDS (asynchronously)
+ * if our wanted caps set expands.
+ */
+int ceph_open(struct inode *inode, struct file *file)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       struct ceph_file_info *cf = file->private_data;
+       struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
+       int err;
+       int flags, fmode, wanted;
+
+       if (cf) {
+               dout("open file %p is already opened\n", file);
+               return 0;
+       }
+
+       /* filter out O_CREAT|O_EXCL; vfs did that already.  yuck. */
+       flags = file->f_flags & ~(O_CREAT|O_EXCL);
+       if (S_ISDIR(inode->i_mode))
+               flags = O_DIRECTORY;  /* mds likes to know */
+
+       dout("open inode %p ino %llx.%llx file %p flags %d (%d)\n", inode,
+            ceph_vinop(inode), file, flags, file->f_flags);
+       fmode = ceph_flags_to_mode(flags);
+       wanted = ceph_caps_for_mode(fmode);
+
+       /* snapped files are read-only */
+       if (ceph_snap(inode) != CEPH_NOSNAP && (file->f_mode & FMODE_WRITE))
+               return -EROFS;
+
+       /* trivially open snapdir */
+       if (ceph_snap(inode) == CEPH_SNAPDIR) {
+               spin_lock(&inode->i_lock);
+               __ceph_get_fmode(ci, fmode);
+               spin_unlock(&inode->i_lock);
+               return ceph_init_file(inode, file, fmode);
+       }
+
+       /*
+        * No need to block if we have any caps.  Update wanted set
+        * asynchronously.
+        */
+       spin_lock(&inode->i_lock);
+       if (__ceph_is_any_real_caps(ci)) {
+               int mds_wanted = __ceph_caps_mds_wanted(ci);
+               int issued = __ceph_caps_issued(ci, NULL);
+
+               dout("open %p fmode %d want %s issued %s using existing\n",
+                    inode, fmode, ceph_cap_string(wanted),
+                    ceph_cap_string(issued));
+               __ceph_get_fmode(ci, fmode);
+               spin_unlock(&inode->i_lock);
+
+               /* adjust wanted? */
+               if ((issued & wanted) != wanted &&
+                   (mds_wanted & wanted) != wanted &&
+                   ceph_snap(inode) != CEPH_SNAPDIR)
+                       ceph_check_caps(ci, 0, NULL);
+
+               return ceph_init_file(inode, file, fmode);
+       } else if (ceph_snap(inode) != CEPH_NOSNAP &&
+                  (ci->i_snap_caps & wanted) == wanted) {
+               __ceph_get_fmode(ci, fmode);
+               spin_unlock(&inode->i_lock);
+               return ceph_init_file(inode, file, fmode);
+       }
+       spin_unlock(&inode->i_lock);
+
+       dout("open fmode %d wants %s\n", fmode, ceph_cap_string(wanted));
+       req = prepare_open_request(inode->i_sb, flags, 0);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto out;
+       }
+       req->r_inode = igrab(inode);
+       req->r_num_caps = 1;
+       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       if (!err)
+               err = ceph_init_file(inode, file, req->r_fmode);
+       ceph_mdsc_put_request(req);
+       dout("open result=%d on %llx.%llx\n", err, ceph_vinop(inode));
+out:
+       return err;
+}
+
+
+/*
+ * Do a lookup + open with a single request.
+ *
+ * If this succeeds, but some subsequent check in the vfs
+ * may_open() fails, the struct *file gets cleaned up (i.e.
+ * ceph_release gets called).  So fear not!
+ */
+/*
+ * flags
+ *  path_lookup_open   -> LOOKUP_OPEN
+ *  path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
+ */
+struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+                               struct nameidata *nd, int mode,
+                               int locked_dir)
+{
+       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct file *file = nd->intent.open.file;
+       struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry);
+       struct ceph_mds_request *req;
+       int err;
+       int flags = nd->intent.open.flags - 1;  /* silly vfs! */
+
+       dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
+            dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
+
+       /* do the open */
+       req = prepare_open_request(dir->i_sb, flags, mode);
+       if (IS_ERR(req))
+               return ERR_PTR(PTR_ERR(req));
+       req->r_dentry = dget(dentry);
+       req->r_num_caps = 2;
+       if (flags & O_CREAT) {
+               req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+               req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       }
+       req->r_locked_dir = dir;           /* caller holds dir->i_mutex */
+       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       dentry = ceph_finish_lookup(req, dentry, err);
+       if (!err && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
+               err = ceph_handle_notrace_create(dir, dentry);
+       if (!err)
+               err = ceph_init_file(req->r_dentry->d_inode, file,
+                                    req->r_fmode);
+       ceph_mdsc_put_request(req);
+       dout("ceph_lookup_open result=%p\n", dentry);
+       return dentry;
+}
+
+int ceph_release(struct inode *inode, struct file *file)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_file_info *cf = file->private_data;
+
+       dout("release inode %p file %p\n", inode, file);
+       ceph_put_fmode(ci, cf->fmode);
+       if (cf->last_readdir)
+               ceph_mdsc_put_request(cf->last_readdir);
+       kfree(cf->last_name);
+       kfree(cf->dir_info);
+       dput(cf->dentry);
+       kmem_cache_free(ceph_file_cachep, cf);
+
+       /* wake up anyone waiting for caps on this inode */
+       wake_up(&ci->i_cap_wq);
+       return 0;
+}
+
+/*
+ * build a vector of user pages
+ */
+static struct page **get_direct_page_vector(const char __user *data,
+                                           int num_pages,
+                                           loff_t off, size_t len)
+{
+       struct page **pages;
+       int rc;
+
+       pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+       if (!pages)
+               return ERR_PTR(-ENOMEM);
+
+       down_read(&current->mm->mmap_sem);
+       rc = get_user_pages(current, current->mm, (unsigned long)data,
+                           num_pages, 0, 0, pages, NULL);
+       up_read(&current->mm->mmap_sem);
+       if (rc < 0)
+               goto fail;
+       return pages;
+
+fail:
+       kfree(pages);
+       return ERR_PTR(rc);
+}
+
+static void put_page_vector(struct page **pages, int num_pages)
+{
+       int i;
+
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       kfree(pages);
+}
+
+void ceph_release_page_vector(struct page **pages, int num_pages)
+{
+       int i;
+
+       for (i = 0; i < num_pages; i++)
+               __free_pages(pages[i], 0);
+       kfree(pages);
+}
+
+/*
+ * allocate a vector new pages
+ */
+static struct page **alloc_page_vector(int num_pages)
+{
+       struct page **pages;
+       int i;
+
+       pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+       if (!pages)
+               return ERR_PTR(-ENOMEM);
+       for (i = 0; i < num_pages; i++) {
+               pages[i] = alloc_page(GFP_NOFS);
+               if (pages[i] == NULL) {
+                       ceph_release_page_vector(pages, i);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
+       return pages;
+}
+
+/*
+ * copy user data into a page vector
+ */
+static int copy_user_to_page_vector(struct page **pages,
+                                   const char __user *data,
+                                   loff_t off, size_t len)
+{
+       int i = 0;
+       int po = off & ~PAGE_CACHE_MASK;
+       int left = len;
+       int l, bad;
+
+       while (left > 0) {
+               l = min_t(int, PAGE_CACHE_SIZE-po, left);
+               bad = copy_from_user(page_address(pages[i]) + po, data, l);
+               if (bad == l)
+                       return -EFAULT;
+               data += l - bad;
+               left -= l - bad;
+               po += l - bad;
+               if (po == PAGE_CACHE_SIZE) {
+                       po = 0;
+                       i++;
+               }
+       }
+       return len;
+}
+
+/*
+ * copy user data from a page vector into a user pointer
+ */
+static int copy_page_vector_to_user(struct page **pages, char __user *data,
+                                   loff_t off, size_t len)
+{
+       int i = 0;
+       int po = off & ~PAGE_CACHE_MASK;
+       int left = len;
+       int l, bad;
+
+       while (left > 0) {
+               l = min_t(int, left, PAGE_CACHE_SIZE-po);
+               bad = copy_to_user(data, page_address(pages[i]) + po, l);
+               if (bad == l)
+                       return -EFAULT;
+               data += l - bad;
+               left -= l - bad;
+               if (po) {
+                       po += l - bad;
+                       if (po == PAGE_CACHE_SIZE)
+                               po = 0;
+               }
+               i++;
+       }
+       return len;
+}
+
+/*
+ * Zero an extent within a page vector.  Offset is relative to the
+ * start of the first page.
+ */
+static void zero_page_vector_range(int off, int len, struct page **pages)
+{
+       int i = off >> PAGE_CACHE_SHIFT;
+
+       off &= ~PAGE_CACHE_MASK;
+
+       dout("zero_page_vector_page %u~%u\n", off, len);
+
+       /* leading partial page? */
+       if (off) {
+               int end = min((int)PAGE_CACHE_SIZE, off + len);
+               dout("zeroing %d %p head from %d\n", i, pages[i],
+                    (int)off);
+               zero_user_segment(pages[i], off, end);
+               len -= (end - off);
+               i++;
+       }
+       while (len >= PAGE_CACHE_SIZE) {
+               dout("zeroing %d %p len=%d\n", i, pages[i], len);
+               zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+               len -= PAGE_CACHE_SIZE;
+               i++;
+       }
+       /* trailing partial page? */
+       if (len) {
+               dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
+               zero_user_segment(pages[i], 0, len);
+       }
+}
+
+
+/*
+ * Read a range of bytes striped over one or more objects.  Iterate over
+ * objects we stripe over.  (That's not atomic, but good enough for now.)
+ *
+ * If we get a short result from the OSD, check against i_size; we need to
+ * only return a short read to the caller if we hit EOF.
+ */
+static int striped_read(struct inode *inode,
+                       u64 off, u64 len,
+                       struct page **pages, int num_pages,
+                       int *checkeof)
+{
+       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       u64 pos, this_len;
+       int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */
+       int left, pages_left;
+       int read;
+       struct page **page_pos;
+       int ret;
+       bool hit_stripe, was_short;
+
+       /*
+        * we may need to do multiple reads.  not atomic, unfortunately.
+        */
+       pos = off;
+       left = len;
+       page_pos = pages;
+       pages_left = num_pages;
+       read = 0;
+
+more:
+       this_len = left;
+       ret = ceph_osdc_readpages(&client->osdc, ceph_vino(inode),
+                                 &ci->i_layout, pos, &this_len,
+                                 ci->i_truncate_seq,
+                                 ci->i_truncate_size,
+                                 page_pos, pages_left);
+       hit_stripe = this_len < left;
+       was_short = ret >= 0 && ret < this_len;
+       if (ret == -ENOENT)
+               ret = 0;
+       dout("striped_read %llu~%u (read %u) got %d%s%s\n", pos, left, read,
+            ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "");
+
+       if (ret > 0) {
+               int didpages =
+                       ((pos & ~PAGE_CACHE_MASK) + ret) >> PAGE_CACHE_SHIFT;
+
+               if (read < pos - off) {
+                       dout(" zero gap %llu to %llu\n", off + read, pos);
+                       zero_page_vector_range(page_off + read,
+                                              pos - off - read, pages);
+               }
+               pos += ret;
+               read = pos - off;
+               left -= ret;
+               page_pos += didpages;
+               pages_left -= didpages;
+
+               /* hit stripe? */
+               if (left && hit_stripe)
+                       goto more;
+       }
+
+       if (was_short) {
+               /* was original extent fully inside i_size? */
+               if (pos + left <= inode->i_size) {
+                       dout("zero tail\n");
+                       zero_page_vector_range(page_off + read, len - read,
+                                              pages);
+                       read = len;
+                       goto out;
+               }
+
+               /* check i_size */
+               *checkeof = 1;
+       }
+
+out:
+       if (ret >= 0)
+               ret = read;
+       dout("striped_read returns %d\n", ret);
+       return ret;
+}
+
+/*
+ * Completely synchronous read and write methods.  Direct from __user
+ * buffer to osd, or directly to user pages (if O_DIRECT).
+ *
+ * If the read spans object boundary, just do multiple reads.
+ */
+static ssize_t ceph_sync_read(struct file *file, char __user *data,
+                             unsigned len, loff_t *poff, int *checkeof)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct page **pages;
+       u64 off = *poff;
+       int num_pages = calc_pages_for(off, len);
+       int ret;
+
+       dout("sync_read on file %p %llu~%u %s\n", file, off, len,
+            (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
+
+       if (file->f_flags & O_DIRECT) {
+               pages = get_direct_page_vector(data, num_pages, off, len);
+
+               /*
+                * flush any page cache pages in this range.  this
+                * will make concurrent normal and O_DIRECT io slow,
+                * but it will at least behave sensibly when they are
+                * in sequence.
+                */
+       } else {
+               pages = alloc_page_vector(num_pages);
+       }
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       ret = filemap_write_and_wait(inode->i_mapping);
+       if (ret < 0)
+               goto done;
+
+       ret = striped_read(inode, off, len, pages, num_pages, checkeof);
+
+       if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
+               ret = copy_page_vector_to_user(pages, data, off, ret);
+       if (ret >= 0)
+               *poff = off + ret;
+
+done:
+       if (file->f_flags & O_DIRECT)
+               put_page_vector(pages, num_pages);
+       else
+               ceph_release_page_vector(pages, num_pages);
+       dout("sync_read result %d\n", ret);
+       return ret;
+}
+
+/*
+ * Write commit callback, called if we requested both an ACK and
+ * ONDISK commit reply from the OSD.
+ */
+static void sync_write_commit(struct ceph_osd_request *req,
+                             struct ceph_msg *msg)
+{
+       struct ceph_inode_info *ci = ceph_inode(req->r_inode);
+
+       dout("sync_write_commit %p tid %llu\n", req, req->r_tid);
+       spin_lock(&ci->i_unsafe_lock);
+       list_del_init(&req->r_unsafe_item);
+       spin_unlock(&ci->i_unsafe_lock);
+       ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
+}
+
+/*
+ * Synchronous write, straight from __user pointer or user pages (if
+ * O_DIRECT).
+ *
+ * If write spans object boundary, just do multiple writes.  (For a
+ * correct atomic write, we should e.g. take write locks on all
+ * objects, rollback on failure, etc.)
+ */
+static ssize_t ceph_sync_write(struct file *file, const char __user *data,
+                              size_t left, loff_t *offset)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_osd_request *req;
+       struct page **pages;
+       int num_pages;
+       long long unsigned pos;
+       u64 len;
+       int written = 0;
+       int flags;
+       int do_sync = 0;
+       int check_caps = 0;
+       int ret;
+       struct timespec mtime = CURRENT_TIME;
+
+       if (ceph_snap(file->f_dentry->d_inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       dout("sync_write on file %p %lld~%u %s\n", file, *offset,
+            (unsigned)left, (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
+
+       if (file->f_flags & O_APPEND)
+               pos = i_size_read(inode);
+       else
+               pos = *offset;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
+       if (ret < 0)
+               return ret;
+
+       ret = invalidate_inode_pages2_range(inode->i_mapping,
+                                           pos >> PAGE_CACHE_SHIFT,
+                                           (pos + left) >> PAGE_CACHE_SHIFT);
+       if (ret < 0)
+               dout("invalidate_inode_pages2_range returned %d\n", ret);
+
+       flags = CEPH_OSD_FLAG_ORDERSNAP |
+               CEPH_OSD_FLAG_ONDISK |
+               CEPH_OSD_FLAG_WRITE;
+       if ((file->f_flags & (O_SYNC|O_DIRECT)) == 0)
+               flags |= CEPH_OSD_FLAG_ACK;
+       else
+               do_sync = 1;
+
+       /*
+        * we may need to do multiple writes here if we span an object
+        * boundary.  this isn't atomic, unfortunately.  :(
+        */
+more:
+       len = left;
+       req = ceph_osdc_new_request(&client->osdc, &ci->i_layout,
+                                   ceph_vino(inode), pos, &len,
+                                   CEPH_OSD_OP_WRITE, flags,
+                                   ci->i_snap_realm->cached_context,
+                                   do_sync,
+                                   ci->i_truncate_seq, ci->i_truncate_size,
+                                   &mtime, false, 2);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       num_pages = calc_pages_for(pos, len);
+
+       if (file->f_flags & O_DIRECT) {
+               pages = get_direct_page_vector(data, num_pages, pos, len);
+               if (IS_ERR(pages)) {
+                       ret = PTR_ERR(pages);
+                       goto out;
+               }
+
+               /*
+                * throw out any page cache pages in this range. this
+                * may block.
+                */
+               truncate_inode_pages_range(inode->i_mapping, pos, pos+len);
+       } else {
+               pages = alloc_page_vector(num_pages);
+               if (IS_ERR(pages)) {
+                       ret = PTR_ERR(pages);
+                       goto out;
+               }
+               ret = copy_user_to_page_vector(pages, data, pos, len);
+               if (ret < 0) {
+                       ceph_release_page_vector(pages, num_pages);
+                       goto out;
+               }
+
+               if ((file->f_flags & O_SYNC) == 0) {
+                       /* get a second commit callback */
+                       req->r_safe_callback = sync_write_commit;
+                       req->r_own_pages = 1;
+               }
+       }
+       req->r_pages = pages;
+       req->r_num_pages = num_pages;
+       req->r_inode = inode;
+
+       ret = ceph_osdc_start_request(&client->osdc, req, false);
+       if (!ret) {
+               if (req->r_safe_callback) {
+                       /*
+                        * Add to inode unsafe list only after we
+                        * start_request so that a tid has been assigned.
+                        */
+                       spin_lock(&ci->i_unsafe_lock);
+                       list_add(&ci->i_unsafe_writes, &req->r_unsafe_item);
+                       spin_unlock(&ci->i_unsafe_lock);
+                       ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
+               }
+               ret = ceph_osdc_wait_request(&client->osdc, req);
+       }
+
+       if (file->f_flags & O_DIRECT)
+               put_page_vector(pages, num_pages);
+       else if (file->f_flags & O_SYNC)
+               ceph_release_page_vector(pages, num_pages);
+
+out:
+       ceph_osdc_put_request(req);
+       if (ret == 0) {
+               pos += len;
+               written += len;
+               left -= len;
+               if (left)
+                       goto more;
+
+               ret = written;
+               *offset = pos;
+               if (pos > i_size_read(inode))
+                       check_caps = ceph_inode_set_size(inode, pos);
+               if (check_caps)
+                       ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY,
+                                       NULL);
+       }
+       return ret;
+}
+
+/*
+ * Wrap generic_file_aio_read with checks for cap bits on the inode.
+ * Atomically grab references, so that those bits are not released
+ * back to the MDS mid-read.
+ *
+ * Hmm, the sync read case isn't actually async... should it be?
+ */
+static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                            unsigned long nr_segs, loff_t pos)
+{
+       struct file *filp = iocb->ki_filp;
+       loff_t *ppos = &iocb->ki_pos;
+       size_t len = iov->iov_len;
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       void *base = iov->iov_base;
+       ssize_t ret;
+       int got = 0;
+       int checkeof = 0, read = 0;
+
+       dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
+            inode, ceph_vinop(inode), pos, (unsigned)len, inode);
+again:
+       __ceph_do_pending_vmtruncate(inode);
+       ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE,
+                           &got, -1);
+       if (ret < 0)
+               goto out;
+       dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
+            inode, ceph_vinop(inode), pos, (unsigned)len,
+            ceph_cap_string(got));
+
+       if ((got & CEPH_CAP_FILE_CACHE) == 0 ||
+           (iocb->ki_filp->f_flags & O_DIRECT) ||
+           (inode->i_sb->s_flags & MS_SYNCHRONOUS))
+               /* hmm, this isn't really async... */
+               ret = ceph_sync_read(filp, base, len, ppos, &checkeof);
+       else
+               ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+out:
+       dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
+            inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
+       ceph_put_cap_refs(ci, got);
+
+       if (checkeof && ret >= 0) {
+               int statret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
+
+               /* hit EOF or hole? */
+               if (statret == 0 && *ppos < inode->i_size) {
+                       dout("aio_read sync_read hit hole, reading more\n");
+                       read += ret;
+                       base += ret;
+                       len -= ret;
+                       checkeof = 0;
+                       goto again;
+               }
+       }
+       if (ret >= 0)
+               ret += read;
+
+       return ret;
+}
+
+/*
+ * Take cap references to avoid releasing caps to MDS mid-write.
+ *
+ * If we are synchronous, and write with an old snap context, the OSD
+ * may return EOLDSNAPC.  In that case, retry the write.. _after_
+ * dropping our cap refs and allowing the pending snap to logically
+ * complete _before_ this write occurs.
+ *
+ * If we are near ENOSPC, write synchronously.
+ */
+static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                      unsigned long nr_segs, loff_t pos)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+       loff_t endoff = pos + iov->iov_len;
+       int got = 0;
+       int ret, err;
+
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+retry_snap:
+       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
+               return -ENOSPC;
+       __ceph_do_pending_vmtruncate(inode);
+       dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
+            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+            inode->i_size);
+       ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER,
+                           &got, endoff);
+       if (ret < 0)
+               goto out;
+
+       dout("aio_write %p %llx.%llx %llu~%u  got cap refs on %s\n",
+            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+            ceph_cap_string(got));
+
+       if ((got & CEPH_CAP_FILE_BUFFER) == 0 ||
+           (iocb->ki_filp->f_flags & O_DIRECT) ||
+           (inode->i_sb->s_flags & MS_SYNCHRONOUS)) {
+               ret = ceph_sync_write(file, iov->iov_base, iov->iov_len,
+                       &iocb->ki_pos);
+       } else {
+               ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+               if ((ret >= 0 || ret == -EIOCBQUEUED) &&
+                   ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host)
+                    || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) {
+                       err = vfs_fsync_range(file, file->f_path.dentry,
+                                             pos, pos + ret - 1, 1);
+                       if (err < 0)
+                               ret = err;
+               }
+       }
+       if (ret >= 0) {
+               spin_lock(&inode->i_lock);
+               __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+               spin_unlock(&inode->i_lock);
+       }
+
+out:
+       dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
+            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+            ceph_cap_string(got));
+       ceph_put_cap_refs(ci, got);
+
+       if (ret == -EOLDSNAPC) {
+               dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n",
+                    inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len);
+               goto retry_snap;
+       }
+
+       return ret;
+}
+
+/*
+ * llseek.  be sure to verify file size on SEEK_END.
+ */
+static loff_t ceph_llseek(struct file *file, loff_t offset, int origin)
+{
+       struct inode *inode = file->f_mapping->host;
+       int ret;
+
+       mutex_lock(&inode->i_mutex);
+       __ceph_do_pending_vmtruncate(inode);
+       switch (origin) {
+       case SEEK_END:
+               ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
+               if (ret < 0) {
+                       offset = ret;
+                       goto out;
+               }
+               offset += inode->i_size;
+               break;
+       case SEEK_CUR:
+               /*
+                * Here we special-case the lseek(fd, 0, SEEK_CUR)
+                * position-querying operation.  Avoid rewriting the "same"
+                * f_pos value back to the file because a concurrent read(),
+                * write() or lseek() might have altered it
+                */
+               if (offset == 0) {
+                       offset = file->f_pos;
+                       goto out;
+               }
+               offset += file->f_pos;
+               break;
+       }
+
+       if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
+               offset = -EINVAL;
+               goto out;
+       }
+
+       /* Special lock needed here? */
+       if (offset != file->f_pos) {
+               file->f_pos = offset;
+               file->f_version = 0;
+       }
+
+out:
+       mutex_unlock(&inode->i_mutex);
+       return offset;
+}
+
+const struct file_operations ceph_file_fops = {
+       .open = ceph_open,
+       .release = ceph_release,
+       .llseek = ceph_llseek,
+       .read = do_sync_read,
+       .write = do_sync_write,
+       .aio_read = ceph_aio_read,
+       .aio_write = ceph_aio_write,
+       .mmap = ceph_mmap,
+       .fsync = ceph_fsync,
+       .splice_read = generic_file_splice_read,
+       .splice_write = generic_file_splice_write,
+       .unlocked_ioctl = ceph_ioctl,
+       .compat_ioctl   = ceph_ioctl,
+};
+
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
new file mode 100644 (file)
index 0000000..7abe1ae
--- /dev/null
@@ -0,0 +1,1750 @@
+#include "ceph_debug.h"
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/namei.h>
+#include <linux/writeback.h>
+#include <linux/vmalloc.h>
+#include <linux/pagevec.h>
+
+#include "super.h"
+#include "decode.h"
+
+/*
+ * Ceph inode operations
+ *
+ * Implement basic inode helpers (get, alloc) and inode ops (getattr,
+ * setattr, etc.), xattr helpers, and helpers for assimilating
+ * metadata returned by the MDS into our cache.
+ *
+ * Also define helpers for doing asynchronous writeback, invalidation,
+ * and truncation for the benefit of those who can't afford to block
+ * (typically because they are in the message handler path).
+ */
+
+static const struct inode_operations ceph_symlink_iops;
+
+static void ceph_invalidate_work(struct work_struct *work);
+static void ceph_writeback_work(struct work_struct *work);
+static void ceph_vmtruncate_work(struct work_struct *work);
+
+/*
+ * find or create an inode, given the ceph ino number
+ */
+struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
+{
+       struct inode *inode;
+       ino_t t = ceph_vino_to_ino(vino);
+
+       inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino);
+       if (inode == NULL)
+               return ERR_PTR(-ENOMEM);
+       if (inode->i_state & I_NEW) {
+               dout("get_inode created new inode %p %llx.%llx ino %llx\n",
+                    inode, ceph_vinop(inode), (u64)inode->i_ino);
+               unlock_new_inode(inode);
+       }
+
+       dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino,
+            vino.snap, inode);
+       return inode;
+}
+
+/*
+ * get/constuct snapdir inode for a given directory
+ */
+struct inode *ceph_get_snapdir(struct inode *parent)
+{
+       struct ceph_vino vino = {
+               .ino = ceph_ino(parent),
+               .snap = CEPH_SNAPDIR,
+       };
+       struct inode *inode = ceph_get_inode(parent->i_sb, vino);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       BUG_ON(!S_ISDIR(parent->i_mode));
+       if (IS_ERR(inode))
+               return ERR_PTR(PTR_ERR(inode));
+       inode->i_mode = parent->i_mode;
+       inode->i_uid = parent->i_uid;
+       inode->i_gid = parent->i_gid;
+       inode->i_op = &ceph_dir_iops;
+       inode->i_fop = &ceph_dir_fops;
+       ci->i_snap_caps = CEPH_CAP_PIN; /* so we can open */
+       ci->i_rbytes = 0;
+       return inode;
+}
+
+const struct inode_operations ceph_file_iops = {
+       .permission = ceph_permission,
+       .setattr = ceph_setattr,
+       .getattr = ceph_getattr,
+       .setxattr = ceph_setxattr,
+       .getxattr = ceph_getxattr,
+       .listxattr = ceph_listxattr,
+       .removexattr = ceph_removexattr,
+};
+
+
+/*
+ * We use a 'frag tree' to keep track of the MDS's directory fragments
+ * for a given inode (usually there is just a single fragment).  We
+ * need to know when a child frag is delegated to a new MDS, or when
+ * it is flagged as replicated, so we can direct our requests
+ * accordingly.
+ */
+
+/*
+ * find/create a frag in the tree
+ */
+static struct ceph_inode_frag *__get_or_create_frag(struct ceph_inode_info *ci,
+                                                   u32 f)
+{
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+       struct ceph_inode_frag *frag;
+       int c;
+
+       p = &ci->i_fragtree.rb_node;
+       while (*p) {
+               parent = *p;
+               frag = rb_entry(parent, struct ceph_inode_frag, node);
+               c = ceph_frag_compare(f, frag->frag);
+               if (c < 0)
+                       p = &(*p)->rb_left;
+               else if (c > 0)
+                       p = &(*p)->rb_right;
+               else
+                       return frag;
+       }
+
+       frag = kmalloc(sizeof(*frag), GFP_NOFS);
+       if (!frag) {
+               pr_err("__get_or_create_frag ENOMEM on %p %llx.%llx "
+                      "frag %x\n", &ci->vfs_inode,
+                      ceph_vinop(&ci->vfs_inode), f);
+               return ERR_PTR(-ENOMEM);
+       }
+       frag->frag = f;
+       frag->split_by = 0;
+       frag->mds = -1;
+       frag->ndist = 0;
+
+       rb_link_node(&frag->node, parent, p);
+       rb_insert_color(&frag->node, &ci->i_fragtree);
+
+       dout("get_or_create_frag added %llx.%llx frag %x\n",
+            ceph_vinop(&ci->vfs_inode), f);
+       return frag;
+}
+
+/*
+ * find a specific frag @f
+ */
+struct ceph_inode_frag *__ceph_find_frag(struct ceph_inode_info *ci, u32 f)
+{
+       struct rb_node *n = ci->i_fragtree.rb_node;
+
+       while (n) {
+               struct ceph_inode_frag *frag =
+                       rb_entry(n, struct ceph_inode_frag, node);
+               int c = ceph_frag_compare(f, frag->frag);
+               if (c < 0)
+                       n = n->rb_left;
+               else if (c > 0)
+                       n = n->rb_right;
+               else
+                       return frag;
+       }
+       return NULL;
+}
+
+/*
+ * Choose frag containing the given value @v.  If @pfrag is
+ * specified, copy the frag delegation info to the caller if
+ * it is present.
+ */
+u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
+                    struct ceph_inode_frag *pfrag,
+                    int *found)
+{
+       u32 t = ceph_frag_make(0, 0);
+       struct ceph_inode_frag *frag;
+       unsigned nway, i;
+       u32 n;
+
+       if (found)
+               *found = 0;
+
+       mutex_lock(&ci->i_fragtree_mutex);
+       while (1) {
+               WARN_ON(!ceph_frag_contains_value(t, v));
+               frag = __ceph_find_frag(ci, t);
+               if (!frag)
+                       break; /* t is a leaf */
+               if (frag->split_by == 0) {
+                       if (pfrag)
+                               memcpy(pfrag, frag, sizeof(*pfrag));
+                       if (found)
+                               *found = 1;
+                       break;
+               }
+
+               /* choose child */
+               nway = 1 << frag->split_by;
+               dout("choose_frag(%x) %x splits by %d (%d ways)\n", v, t,
+                    frag->split_by, nway);
+               for (i = 0; i < nway; i++) {
+                       n = ceph_frag_make_child(t, frag->split_by, i);
+                       if (ceph_frag_contains_value(n, v)) {
+                               t = n;
+                               break;
+                       }
+               }
+               BUG_ON(i == nway);
+       }
+       dout("choose_frag(%x) = %x\n", v, t);
+
+       mutex_unlock(&ci->i_fragtree_mutex);
+       return t;
+}
+
+/*
+ * Process dirfrag (delegation) info from the mds.  Include leaf
+ * fragment in tree ONLY if ndist > 0.  Otherwise, only
+ * branches/splits are included in i_fragtree)
+ */
+static int ceph_fill_dirfrag(struct inode *inode,
+                            struct ceph_mds_reply_dirfrag *dirinfo)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_inode_frag *frag;
+       u32 id = le32_to_cpu(dirinfo->frag);
+       int mds = le32_to_cpu(dirinfo->auth);
+       int ndist = le32_to_cpu(dirinfo->ndist);
+       int i;
+       int err = 0;
+
+       mutex_lock(&ci->i_fragtree_mutex);
+       if (ndist == 0) {
+               /* no delegation info needed. */
+               frag = __ceph_find_frag(ci, id);
+               if (!frag)
+                       goto out;
+               if (frag->split_by == 0) {
+                       /* tree leaf, remove */
+                       dout("fill_dirfrag removed %llx.%llx frag %x"
+                            " (no ref)\n", ceph_vinop(inode), id);
+                       rb_erase(&frag->node, &ci->i_fragtree);
+                       kfree(frag);
+               } else {
+                       /* tree branch, keep and clear */
+                       dout("fill_dirfrag cleared %llx.%llx frag %x"
+                            " referral\n", ceph_vinop(inode), id);
+                       frag->mds = -1;
+                       frag->ndist = 0;
+               }
+               goto out;
+       }
+
+
+       /* find/add this frag to store mds delegation info */
+       frag = __get_or_create_frag(ci, id);
+       if (IS_ERR(frag)) {
+               /* this is not the end of the world; we can continue
+                  with bad/inaccurate delegation info */
+               pr_err("fill_dirfrag ENOMEM on mds ref %llx.%llx fg %x\n",
+                      ceph_vinop(inode), le32_to_cpu(dirinfo->frag));
+               err = -ENOMEM;
+               goto out;
+       }
+
+       frag->mds = mds;
+       frag->ndist = min_t(u32, ndist, CEPH_MAX_DIRFRAG_REP);
+       for (i = 0; i < frag->ndist; i++)
+               frag->dist[i] = le32_to_cpu(dirinfo->dist[i]);
+       dout("fill_dirfrag %llx.%llx frag %x ndist=%d\n",
+            ceph_vinop(inode), frag->frag, frag->ndist);
+
+out:
+       mutex_unlock(&ci->i_fragtree_mutex);
+       return err;
+}
+
+
+/*
+ * initialize a newly allocated inode.
+ */
+struct inode *ceph_alloc_inode(struct super_block *sb)
+{
+       struct ceph_inode_info *ci;
+       int i;
+
+       ci = kmem_cache_alloc(ceph_inode_cachep, GFP_NOFS);
+       if (!ci)
+               return NULL;
+
+       dout("alloc_inode %p\n", &ci->vfs_inode);
+
+       ci->i_version = 0;
+       ci->i_time_warp_seq = 0;
+       ci->i_ceph_flags = 0;
+       ci->i_release_count = 0;
+       ci->i_symlink = NULL;
+
+       ci->i_fragtree = RB_ROOT;
+       mutex_init(&ci->i_fragtree_mutex);
+
+       ci->i_xattrs.blob = NULL;
+       ci->i_xattrs.prealloc_blob = NULL;
+       ci->i_xattrs.dirty = false;
+       ci->i_xattrs.index = RB_ROOT;
+       ci->i_xattrs.count = 0;
+       ci->i_xattrs.names_size = 0;
+       ci->i_xattrs.vals_size = 0;
+       ci->i_xattrs.version = 0;
+       ci->i_xattrs.index_version = 0;
+
+       ci->i_caps = RB_ROOT;
+       ci->i_auth_cap = NULL;
+       ci->i_dirty_caps = 0;
+       ci->i_flushing_caps = 0;
+       INIT_LIST_HEAD(&ci->i_dirty_item);
+       INIT_LIST_HEAD(&ci->i_flushing_item);
+       ci->i_cap_flush_seq = 0;
+       ci->i_cap_flush_last_tid = 0;
+       memset(&ci->i_cap_flush_tid, 0, sizeof(ci->i_cap_flush_tid));
+       init_waitqueue_head(&ci->i_cap_wq);
+       ci->i_hold_caps_min = 0;
+       ci->i_hold_caps_max = 0;
+       INIT_LIST_HEAD(&ci->i_cap_delay_list);
+       ci->i_cap_exporting_mds = 0;
+       ci->i_cap_exporting_mseq = 0;
+       ci->i_cap_exporting_issued = 0;
+       INIT_LIST_HEAD(&ci->i_cap_snaps);
+       ci->i_head_snapc = NULL;
+       ci->i_snap_caps = 0;
+
+       for (i = 0; i < CEPH_FILE_MODE_NUM; i++)
+               ci->i_nr_by_mode[i] = 0;
+
+       ci->i_truncate_seq = 0;
+       ci->i_truncate_size = 0;
+       ci->i_truncate_pending = 0;
+
+       ci->i_max_size = 0;
+       ci->i_reported_size = 0;
+       ci->i_wanted_max_size = 0;
+       ci->i_requested_max_size = 0;
+
+       ci->i_pin_ref = 0;
+       ci->i_rd_ref = 0;
+       ci->i_rdcache_ref = 0;
+       ci->i_wr_ref = 0;
+       ci->i_wrbuffer_ref = 0;
+       ci->i_wrbuffer_ref_head = 0;
+       ci->i_shared_gen = 0;
+       ci->i_rdcache_gen = 0;
+       ci->i_rdcache_revoking = 0;
+
+       INIT_LIST_HEAD(&ci->i_unsafe_writes);
+       INIT_LIST_HEAD(&ci->i_unsafe_dirops);
+       spin_lock_init(&ci->i_unsafe_lock);
+
+       ci->i_snap_realm = NULL;
+       INIT_LIST_HEAD(&ci->i_snap_realm_item);
+       INIT_LIST_HEAD(&ci->i_snap_flush_item);
+
+       INIT_WORK(&ci->i_wb_work, ceph_writeback_work);
+       INIT_WORK(&ci->i_pg_inv_work, ceph_invalidate_work);
+
+       INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work);
+
+       return &ci->vfs_inode;
+}
+
+void ceph_destroy_inode(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_inode_frag *frag;
+       struct rb_node *n;
+
+       dout("destroy_inode %p ino %llx.%llx\n", inode, ceph_vinop(inode));
+
+       ceph_queue_caps_release(inode);
+
+       kfree(ci->i_symlink);
+       while ((n = rb_first(&ci->i_fragtree)) != NULL) {
+               frag = rb_entry(n, struct ceph_inode_frag, node);
+               rb_erase(n, &ci->i_fragtree);
+               kfree(frag);
+       }
+
+       __ceph_destroy_xattrs(ci);
+       if (ci->i_xattrs.blob)
+               ceph_buffer_put(ci->i_xattrs.blob);
+       if (ci->i_xattrs.prealloc_blob)
+               ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+
+       kmem_cache_free(ceph_inode_cachep, ci);
+}
+
+
+/*
+ * Helpers to fill in size, ctime, mtime, and atime.  We have to be
+ * careful because either the client or MDS may have more up to date
+ * info, depending on which capabilities are held, and whether
+ * time_warp_seq or truncate_seq have increased.  (Ordinarily, mtime
+ * and size are monotonically increasing, except when utimes() or
+ * truncate() increments the corresponding _seq values.)
+ */
+int ceph_fill_file_size(struct inode *inode, int issued,
+                       u32 truncate_seq, u64 truncate_size, u64 size)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int queue_trunc = 0;
+
+       if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) > 0 ||
+           (truncate_seq == ci->i_truncate_seq && size > inode->i_size)) {
+               dout("size %lld -> %llu\n", inode->i_size, size);
+               inode->i_size = size;
+               inode->i_blocks = (size + (1<<9) - 1) >> 9;
+               ci->i_reported_size = size;
+               if (truncate_seq != ci->i_truncate_seq) {
+                       dout("truncate_seq %u -> %u\n",
+                            ci->i_truncate_seq, truncate_seq);
+                       ci->i_truncate_seq = truncate_seq;
+                       /*
+                        * If we hold relevant caps, or in the case where we're
+                        * not the only client referencing this file and we
+                        * don't hold those caps, then we need to check whether
+                        * the file is either opened or mmaped
+                        */
+                       if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
+                                     CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
+                                     CEPH_CAP_FILE_EXCL)) ||
+                           mapping_mapped(inode->i_mapping) ||
+                           __ceph_caps_file_wanted(ci)) {
+                               ci->i_truncate_pending++;
+                               queue_trunc = 1;
+                       }
+               }
+       }
+       if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) >= 0 &&
+           ci->i_truncate_size != truncate_size) {
+               dout("truncate_size %lld -> %llu\n", ci->i_truncate_size,
+                    truncate_size);
+               ci->i_truncate_size = truncate_size;
+       }
+       return queue_trunc;
+}
+
+void ceph_fill_file_time(struct inode *inode, int issued,
+                        u64 time_warp_seq, struct timespec *ctime,
+                        struct timespec *mtime, struct timespec *atime)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int warn = 0;
+
+       if (issued & (CEPH_CAP_FILE_EXCL|
+                     CEPH_CAP_FILE_WR|
+                     CEPH_CAP_FILE_BUFFER)) {
+               if (timespec_compare(ctime, &inode->i_ctime) > 0) {
+                       dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n",
+                            inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+                            ctime->tv_sec, ctime->tv_nsec);
+                       inode->i_ctime = *ctime;
+               }
+               if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) > 0) {
+                       /* the MDS did a utimes() */
+                       dout("mtime %ld.%09ld -> %ld.%09ld "
+                            "tw %d -> %d\n",
+                            inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+                            mtime->tv_sec, mtime->tv_nsec,
+                            ci->i_time_warp_seq, (int)time_warp_seq);
+
+                       inode->i_mtime = *mtime;
+                       inode->i_atime = *atime;
+                       ci->i_time_warp_seq = time_warp_seq;
+               } else if (time_warp_seq == ci->i_time_warp_seq) {
+                       /* nobody did utimes(); take the max */
+                       if (timespec_compare(mtime, &inode->i_mtime) > 0) {
+                               dout("mtime %ld.%09ld -> %ld.%09ld inc\n",
+                                    inode->i_mtime.tv_sec,
+                                    inode->i_mtime.tv_nsec,
+                                    mtime->tv_sec, mtime->tv_nsec);
+                               inode->i_mtime = *mtime;
+                       }
+                       if (timespec_compare(atime, &inode->i_atime) > 0) {
+                               dout("atime %ld.%09ld -> %ld.%09ld inc\n",
+                                    inode->i_atime.tv_sec,
+                                    inode->i_atime.tv_nsec,
+                                    atime->tv_sec, atime->tv_nsec);
+                               inode->i_atime = *atime;
+                       }
+               } else if (issued & CEPH_CAP_FILE_EXCL) {
+                       /* we did a utimes(); ignore mds values */
+               } else {
+                       warn = 1;
+               }
+       } else {
+               /* we have no write caps; whatever the MDS says is true */
+               if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) {
+                       inode->i_ctime = *ctime;
+                       inode->i_mtime = *mtime;
+                       inode->i_atime = *atime;
+                       ci->i_time_warp_seq = time_warp_seq;
+               } else {
+                       warn = 1;
+               }
+       }
+       if (warn) /* time_warp_seq shouldn't go backwards */
+               dout("%p mds time_warp_seq %llu < %u\n",
+                    inode, time_warp_seq, ci->i_time_warp_seq);
+}
+
+/*
+ * Populate an inode based on info from mds.  May be called on new or
+ * existing inodes.
+ */
+static int fill_inode(struct inode *inode,
+                     struct ceph_mds_reply_info_in *iinfo,
+                     struct ceph_mds_reply_dirfrag *dirinfo,
+                     struct ceph_mds_session *session,
+                     unsigned long ttl_from, int cap_fmode,
+                     struct ceph_cap_reservation *caps_reservation)
+{
+       struct ceph_mds_reply_inode *info = iinfo->in;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int i;
+       int issued, implemented;
+       struct timespec mtime, atime, ctime;
+       u32 nsplits;
+       struct ceph_buffer *xattr_blob = NULL;
+       int err = 0;
+       int queue_trunc = 0;
+
+       dout("fill_inode %p ino %llx.%llx v %llu had %llu\n",
+            inode, ceph_vinop(inode), le64_to_cpu(info->version),
+            ci->i_version);
+
+       /*
+        * prealloc xattr data, if it looks like we'll need it.  only
+        * if len > 4 (meaning there are actually xattrs; the first 4
+        * bytes are the xattr count).
+        */
+       if (iinfo->xattr_len > 4) {
+               xattr_blob = ceph_buffer_new(iinfo->xattr_len, GFP_NOFS);
+               if (!xattr_blob)
+                       pr_err("fill_inode ENOMEM xattr blob %d bytes\n",
+                              iinfo->xattr_len);
+       }
+
+       spin_lock(&inode->i_lock);
+
+       /*
+        * provided version will be odd if inode value is projected,
+        * even if stable.  skip the update if we have a newer info
+        * (e.g., due to inode info racing form multiple MDSs), or if
+        * we are getting projected (unstable) inode info.
+        */
+       if (le64_to_cpu(info->version) > 0 &&
+           (ci->i_version & ~1) > le64_to_cpu(info->version))
+               goto no_change;
+
+       issued = __ceph_caps_issued(ci, &implemented);
+       issued |= implemented | __ceph_caps_dirty(ci);
+
+       /* update inode */
+       ci->i_version = le64_to_cpu(info->version);
+       inode->i_version++;
+       inode->i_rdev = le32_to_cpu(info->rdev);
+
+       if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {
+               inode->i_mode = le32_to_cpu(info->mode);
+               inode->i_uid = le32_to_cpu(info->uid);
+               inode->i_gid = le32_to_cpu(info->gid);
+               dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
+                    inode->i_uid, inode->i_gid);
+       }
+
+       if ((issued & CEPH_CAP_LINK_EXCL) == 0)
+               inode->i_nlink = le32_to_cpu(info->nlink);
+
+       /* be careful with mtime, atime, size */
+       ceph_decode_timespec(&atime, &info->atime);
+       ceph_decode_timespec(&mtime, &info->mtime);
+       ceph_decode_timespec(&ctime, &info->ctime);
+       queue_trunc = ceph_fill_file_size(inode, issued,
+                                         le32_to_cpu(info->truncate_seq),
+                                         le64_to_cpu(info->truncate_size),
+                                         le64_to_cpu(info->size));
+       ceph_fill_file_time(inode, issued,
+                           le32_to_cpu(info->time_warp_seq),
+                           &ctime, &mtime, &atime);
+
+       ci->i_max_size = le64_to_cpu(info->max_size);
+       ci->i_layout = info->layout;
+       inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
+
+       /* xattrs */
+       /* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */
+       if ((issued & CEPH_CAP_XATTR_EXCL) == 0 &&
+           le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) {
+               if (ci->i_xattrs.blob)
+                       ceph_buffer_put(ci->i_xattrs.blob);
+               ci->i_xattrs.blob = xattr_blob;
+               if (xattr_blob)
+                       memcpy(ci->i_xattrs.blob->vec.iov_base,
+                              iinfo->xattr_data, iinfo->xattr_len);
+               ci->i_xattrs.version = le64_to_cpu(info->xattr_version);
+       }
+
+       inode->i_mapping->a_ops = &ceph_aops;
+       inode->i_mapping->backing_dev_info =
+               &ceph_client(inode->i_sb)->backing_dev_info;
+
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFIFO:
+       case S_IFBLK:
+       case S_IFCHR:
+       case S_IFSOCK:
+               init_special_inode(inode, inode->i_mode, inode->i_rdev);
+               inode->i_op = &ceph_file_iops;
+               break;
+       case S_IFREG:
+               inode->i_op = &ceph_file_iops;
+               inode->i_fop = &ceph_file_fops;
+               break;
+       case S_IFLNK:
+               inode->i_op = &ceph_symlink_iops;
+               if (!ci->i_symlink) {
+                       int symlen = iinfo->symlink_len;
+                       char *sym;
+
+                       BUG_ON(symlen != inode->i_size);
+                       spin_unlock(&inode->i_lock);
+
+                       err = -ENOMEM;
+                       sym = kmalloc(symlen+1, GFP_NOFS);
+                       if (!sym)
+                               goto out;
+                       memcpy(sym, iinfo->symlink, symlen);
+                       sym[symlen] = 0;
+
+                       spin_lock(&inode->i_lock);
+                       if (!ci->i_symlink)
+                               ci->i_symlink = sym;
+                       else
+                               kfree(sym); /* lost a race */
+               }
+               break;
+       case S_IFDIR:
+               inode->i_op = &ceph_dir_iops;
+               inode->i_fop = &ceph_dir_fops;
+
+               ci->i_files = le64_to_cpu(info->files);
+               ci->i_subdirs = le64_to_cpu(info->subdirs);
+               ci->i_rbytes = le64_to_cpu(info->rbytes);
+               ci->i_rfiles = le64_to_cpu(info->rfiles);
+               ci->i_rsubdirs = le64_to_cpu(info->rsubdirs);
+               ceph_decode_timespec(&ci->i_rctime, &info->rctime);
+
+               /* set dir completion flag? */
+               if (ci->i_files == 0 && ci->i_subdirs == 0 &&
+                   ceph_snap(inode) == CEPH_NOSNAP &&
+                   (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED)) {
+                       dout(" marking %p complete (empty)\n", inode);
+                       ci->i_ceph_flags |= CEPH_I_COMPLETE;
+                       ci->i_max_offset = 2;
+               }
+
+               /* it may be better to set st_size in getattr instead? */
+               if (ceph_test_opt(ceph_client(inode->i_sb), RBYTES))
+                       inode->i_size = ci->i_rbytes;
+               break;
+       default:
+               pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
+                      ceph_vinop(inode), inode->i_mode);
+       }
+
+no_change:
+       spin_unlock(&inode->i_lock);
+
+       /* queue truncate if we saw i_size decrease */
+       if (queue_trunc)
+               ceph_queue_vmtruncate(inode);
+
+       /* populate frag tree */
+       /* FIXME: move me up, if/when version reflects fragtree changes */
+       nsplits = le32_to_cpu(info->fragtree.nsplits);
+       mutex_lock(&ci->i_fragtree_mutex);
+       for (i = 0; i < nsplits; i++) {
+               u32 id = le32_to_cpu(info->fragtree.splits[i].frag);
+               struct ceph_inode_frag *frag = __get_or_create_frag(ci, id);
+
+               if (IS_ERR(frag))
+                       continue;
+               frag->split_by = le32_to_cpu(info->fragtree.splits[i].by);
+               dout(" frag %x split by %d\n", frag->frag, frag->split_by);
+       }
+       mutex_unlock(&ci->i_fragtree_mutex);
+
+       /* were we issued a capability? */
+       if (info->cap.caps) {
+               if (ceph_snap(inode) == CEPH_NOSNAP) {
+                       ceph_add_cap(inode, session,
+                                    le64_to_cpu(info->cap.cap_id),
+                                    cap_fmode,
+                                    le32_to_cpu(info->cap.caps),
+                                    le32_to_cpu(info->cap.wanted),
+                                    le32_to_cpu(info->cap.seq),
+                                    le32_to_cpu(info->cap.mseq),
+                                    le64_to_cpu(info->cap.realm),
+                                    info->cap.flags,
+                                    caps_reservation);
+               } else {
+                       spin_lock(&inode->i_lock);
+                       dout(" %p got snap_caps %s\n", inode,
+                            ceph_cap_string(le32_to_cpu(info->cap.caps)));
+                       ci->i_snap_caps |= le32_to_cpu(info->cap.caps);
+                       if (cap_fmode >= 0)
+                               __ceph_get_fmode(ci, cap_fmode);
+                       spin_unlock(&inode->i_lock);
+               }
+       }
+
+       /* update delegation info? */
+       if (dirinfo)
+               ceph_fill_dirfrag(inode, dirinfo);
+
+       err = 0;
+
+out:
+       if (xattr_blob)
+               ceph_buffer_put(xattr_blob);
+       return err;
+}
+
+/*
+ * caller should hold session s_mutex.
+ */
+static void update_dentry_lease(struct dentry *dentry,
+                               struct ceph_mds_reply_lease *lease,
+                               struct ceph_mds_session *session,
+                               unsigned long from_time)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+       long unsigned duration = le32_to_cpu(lease->duration_ms);
+       long unsigned ttl = from_time + (duration * HZ) / 1000;
+       long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000;
+       struct inode *dir;
+
+       /* only track leases on regular dentries */
+       if (dentry->d_op != &ceph_dentry_ops)
+               return;
+
+       spin_lock(&dentry->d_lock);
+       dout("update_dentry_lease %p mask %d duration %lu ms ttl %lu\n",
+            dentry, le16_to_cpu(lease->mask), duration, ttl);
+
+       /* make lease_rdcache_gen match directory */
+       dir = dentry->d_parent->d_inode;
+       di->lease_shared_gen = ceph_inode(dir)->i_shared_gen;
+
+       if (lease->mask == 0)
+               goto out_unlock;
+
+       if (di->lease_gen == session->s_cap_gen &&
+           time_before(ttl, dentry->d_time))
+               goto out_unlock;  /* we already have a newer lease. */
+
+       if (di->lease_session && di->lease_session != session)
+               goto out_unlock;
+
+       ceph_dentry_lru_touch(dentry);
+
+       if (!di->lease_session)
+               di->lease_session = ceph_get_mds_session(session);
+       di->lease_gen = session->s_cap_gen;
+       di->lease_seq = le32_to_cpu(lease->seq);
+       di->lease_renew_after = half_ttl;
+       di->lease_renew_from = 0;
+       dentry->d_time = ttl;
+out_unlock:
+       spin_unlock(&dentry->d_lock);
+       return;
+}
+
+/*
+ * splice a dentry to an inode.
+ * caller must hold directory i_mutex for this to be safe.
+ *
+ * we will only rehash the resulting dentry if @prehash is
+ * true; @prehash will be set to false (for the benefit of
+ * the caller) if we fail.
+ */
+static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
+                                   bool *prehash)
+{
+       struct dentry *realdn;
+
+       /* dn must be unhashed */
+       if (!d_unhashed(dn))
+               d_drop(dn);
+       realdn = d_materialise_unique(dn, in);
+       if (IS_ERR(realdn)) {
+               pr_err("splice_dentry error %p inode %p ino %llx.%llx\n",
+                      dn, in, ceph_vinop(in));
+               if (prehash)
+                       *prehash = false; /* don't rehash on error */
+               dn = realdn; /* note realdn contains the error */
+               goto out;
+       } else if (realdn) {
+               dout("dn %p (%d) spliced with %p (%d) "
+                    "inode %p ino %llx.%llx\n",
+                    dn, atomic_read(&dn->d_count),
+                    realdn, atomic_read(&realdn->d_count),
+                    realdn->d_inode, ceph_vinop(realdn->d_inode));
+               dput(dn);
+               dn = realdn;
+       } else {
+               BUG_ON(!ceph_dentry(dn));
+
+               dout("dn %p attached to %p ino %llx.%llx\n",
+                    dn, dn->d_inode, ceph_vinop(dn->d_inode));
+       }
+       if ((!prehash || *prehash) && d_unhashed(dn))
+               d_rehash(dn);
+out:
+       return dn;
+}
+
+/*
+ * Set dentry's directory position based on the current dir's max, and
+ * order it in d_subdirs, so that dcache_readdir behaves.
+ */
+static void ceph_set_dentry_offset(struct dentry *dn)
+{
+       struct dentry *dir = dn->d_parent;
+       struct inode *inode = dn->d_parent->d_inode;
+       struct ceph_dentry_info *di;
+
+       BUG_ON(!inode);
+
+       di = ceph_dentry(dn);
+
+       spin_lock(&inode->i_lock);
+       di->offset = ceph_inode(inode)->i_max_offset++;
+       spin_unlock(&inode->i_lock);
+
+       spin_lock(&dcache_lock);
+       spin_lock(&dn->d_lock);
+       list_move_tail(&dir->d_subdirs, &dn->d_u.d_child);
+       dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
+            dn->d_u.d_child.prev, dn->d_u.d_child.next);
+       spin_unlock(&dn->d_lock);
+       spin_unlock(&dcache_lock);
+}
+
+/*
+ * Incorporate results into the local cache.  This is either just
+ * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
+ * after a lookup).
+ *
+ * A reply may contain
+ *         a directory inode along with a dentry.
+ *  and/or a target inode
+ *
+ * Called with snap_rwsem (read).
+ */
+int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
+                   struct ceph_mds_session *session)
+{
+       struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+       struct inode *in = NULL;
+       struct ceph_mds_reply_inode *ininfo;
+       struct ceph_vino vino;
+       int i = 0;
+       int err = 0;
+
+       dout("fill_trace %p is_dentry %d is_target %d\n", req,
+            rinfo->head->is_dentry, rinfo->head->is_target);
+
+#if 0
+       /*
+        * Debugging hook:
+        *
+        * If we resend completed ops to a recovering mds, we get no
+        * trace.  Since that is very rare, pretend this is the case
+        * to ensure the 'no trace' handlers in the callers behave.
+        *
+        * Fill in inodes unconditionally to avoid breaking cap
+        * invariants.
+        */
+       if (rinfo->head->op & CEPH_MDS_OP_WRITE) {
+               pr_info("fill_trace faking empty trace on %lld %s\n",
+                       req->r_tid, ceph_mds_op_name(rinfo->head->op));
+               if (rinfo->head->is_dentry) {
+                       rinfo->head->is_dentry = 0;
+                       err = fill_inode(req->r_locked_dir,
+                                        &rinfo->diri, rinfo->dirfrag,
+                                        session, req->r_request_started, -1);
+               }
+               if (rinfo->head->is_target) {
+                       rinfo->head->is_target = 0;
+                       ininfo = rinfo->targeti.in;
+                       vino.ino = le64_to_cpu(ininfo->ino);
+                       vino.snap = le64_to_cpu(ininfo->snapid);
+                       in = ceph_get_inode(sb, vino);
+                       err = fill_inode(in, &rinfo->targeti, NULL,
+                                        session, req->r_request_started,
+                                        req->r_fmode);
+                       iput(in);
+               }
+       }
+#endif
+
+       if (!rinfo->head->is_target && !rinfo->head->is_dentry) {
+               dout("fill_trace reply is empty!\n");
+               if (rinfo->head->result == 0 && req->r_locked_dir) {
+                       struct ceph_inode_info *ci =
+                               ceph_inode(req->r_locked_dir);
+                       dout(" clearing %p complete (empty trace)\n",
+                            req->r_locked_dir);
+                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+                       ci->i_release_count++;
+               }
+               return 0;
+       }
+
+       if (rinfo->head->is_dentry) {
+               struct inode *dir = req->r_locked_dir;
+
+               err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
+                                session, req->r_request_started, -1,
+                                &req->r_caps_reservation);
+               if (err < 0)
+                       return err;
+       }
+
+       if (rinfo->head->is_dentry && !req->r_aborted) {
+               /*
+                * lookup link rename   : null -> possibly existing inode
+                * mknod symlink mkdir  : null -> new inode
+                * unlink               : linked -> null
+                */
+               struct inode *dir = req->r_locked_dir;
+               struct dentry *dn = req->r_dentry;
+               bool have_dir_cap, have_lease;
+
+               BUG_ON(!dn);
+               BUG_ON(!dir);
+               BUG_ON(dn->d_parent->d_inode != dir);
+               BUG_ON(ceph_ino(dir) !=
+                      le64_to_cpu(rinfo->diri.in->ino));
+               BUG_ON(ceph_snap(dir) !=
+                      le64_to_cpu(rinfo->diri.in->snapid));
+
+               /* do we have a lease on the whole dir? */
+               have_dir_cap =
+                       (le32_to_cpu(rinfo->diri.in->cap.caps) &
+                        CEPH_CAP_FILE_SHARED);
+
+               /* do we have a dn lease? */
+               have_lease = have_dir_cap ||
+                       (le16_to_cpu(rinfo->dlease->mask) &
+                        CEPH_LOCK_DN);
+
+               if (!have_lease)
+                       dout("fill_trace  no dentry lease or dir cap\n");
+
+               /* rename? */
+               if (req->r_old_dentry && req->r_op == CEPH_MDS_OP_RENAME) {
+                       dout(" src %p '%.*s' dst %p '%.*s'\n",
+                            req->r_old_dentry,
+                            req->r_old_dentry->d_name.len,
+                            req->r_old_dentry->d_name.name,
+                            dn, dn->d_name.len, dn->d_name.name);
+                       dout("fill_trace doing d_move %p -> %p\n",
+                            req->r_old_dentry, dn);
+                       d_move(req->r_old_dentry, dn);
+                       dout(" src %p '%.*s' dst %p '%.*s'\n",
+                            req->r_old_dentry,
+                            req->r_old_dentry->d_name.len,
+                            req->r_old_dentry->d_name.name,
+                            dn, dn->d_name.len, dn->d_name.name);
+                       /* ensure target dentry is invalidated, despite
+                          rehashing bug in vfs_rename_dir */
+                       dn->d_time = jiffies;
+                       ceph_dentry(dn)->lease_shared_gen = 0;
+                       /* take overwritten dentry's readdir offset */
+                       ceph_dentry(req->r_old_dentry)->offset =
+                               ceph_dentry(dn)->offset;
+                       dn = req->r_old_dentry;  /* use old_dentry */
+                       in = dn->d_inode;
+               }
+
+               /* null dentry? */
+               if (!rinfo->head->is_target) {
+                       dout("fill_trace null dentry\n");
+                       if (dn->d_inode) {
+                               dout("d_delete %p\n", dn);
+                               d_delete(dn);
+                       } else {
+                               dout("d_instantiate %p NULL\n", dn);
+                               d_instantiate(dn, NULL);
+                               if (have_lease && d_unhashed(dn))
+                                       d_rehash(dn);
+                               update_dentry_lease(dn, rinfo->dlease,
+                                                   session,
+                                                   req->r_request_started);
+                       }
+                       goto done;
+               }
+
+               /* attach proper inode */
+               ininfo = rinfo->targeti.in;
+               vino.ino = le64_to_cpu(ininfo->ino);
+               vino.snap = le64_to_cpu(ininfo->snapid);
+               if (!dn->d_inode) {
+                       in = ceph_get_inode(sb, vino);
+                       if (IS_ERR(in)) {
+                               pr_err("fill_trace bad get_inode "
+                                      "%llx.%llx\n", vino.ino, vino.snap);
+                               err = PTR_ERR(in);
+                               d_delete(dn);
+                               goto done;
+                       }
+                       dn = splice_dentry(dn, in, &have_lease);
+                       if (IS_ERR(dn)) {
+                               err = PTR_ERR(dn);
+                               goto done;
+                       }
+                       req->r_dentry = dn;  /* may have spliced */
+                       ceph_set_dentry_offset(dn);
+                       igrab(in);
+               } else if (ceph_ino(in) == vino.ino &&
+                          ceph_snap(in) == vino.snap) {
+                       igrab(in);
+               } else {
+                       dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
+                            dn, in, ceph_ino(in), ceph_snap(in),
+                            vino.ino, vino.snap);
+                       have_lease = false;
+                       in = NULL;
+               }
+
+               if (have_lease)
+                       update_dentry_lease(dn, rinfo->dlease, session,
+                                           req->r_request_started);
+               dout(" final dn %p\n", dn);
+               i++;
+       } else if (req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
+                  req->r_op == CEPH_MDS_OP_MKSNAP) {
+               struct dentry *dn = req->r_dentry;
+
+               /* fill out a snapdir LOOKUPSNAP dentry */
+               BUG_ON(!dn);
+               BUG_ON(!req->r_locked_dir);
+               BUG_ON(ceph_snap(req->r_locked_dir) != CEPH_SNAPDIR);
+               ininfo = rinfo->targeti.in;
+               vino.ino = le64_to_cpu(ininfo->ino);
+               vino.snap = le64_to_cpu(ininfo->snapid);
+               in = ceph_get_inode(sb, vino);
+               if (IS_ERR(in)) {
+                       pr_err("fill_inode get_inode badness %llx.%llx\n",
+                              vino.ino, vino.snap);
+                       err = PTR_ERR(in);
+                       d_delete(dn);
+                       goto done;
+               }
+               dout(" linking snapped dir %p to dn %p\n", in, dn);
+               dn = splice_dentry(dn, in, NULL);
+               if (IS_ERR(dn)) {
+                       err = PTR_ERR(dn);
+                       goto done;
+               }
+               ceph_set_dentry_offset(dn);
+               req->r_dentry = dn;  /* may have spliced */
+               igrab(in);
+               rinfo->head->is_dentry = 1;  /* fool notrace handlers */
+       }
+
+       if (rinfo->head->is_target) {
+               vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
+               vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
+
+               if (in == NULL || ceph_ino(in) != vino.ino ||
+                   ceph_snap(in) != vino.snap) {
+                       in = ceph_get_inode(sb, vino);
+                       if (IS_ERR(in)) {
+                               err = PTR_ERR(in);
+                               goto done;
+                       }
+               }
+               req->r_target_inode = in;
+
+               err = fill_inode(in,
+                                &rinfo->targeti, NULL,
+                                session, req->r_request_started,
+                                (le32_to_cpu(rinfo->head->result) == 0) ?
+                                req->r_fmode : -1,
+                                &req->r_caps_reservation);
+               if (err < 0) {
+                       pr_err("fill_inode badness %p %llx.%llx\n",
+                              in, ceph_vinop(in));
+                       goto done;
+               }
+       }
+
+done:
+       dout("fill_trace done err=%d\n", err);
+       return err;
+}
+
+/*
+ * Prepopulate our cache with readdir results, leases, etc.
+ */
+int ceph_readdir_prepopulate(struct ceph_mds_request *req,
+                            struct ceph_mds_session *session)
+{
+       struct dentry *parent = req->r_dentry;
+       struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+       struct qstr dname;
+       struct dentry *dn;
+       struct inode *in;
+       int err = 0, i;
+       struct inode *snapdir = NULL;
+       struct ceph_mds_request_head *rhead = req->r_request->front.iov_base;
+       u64 frag = le32_to_cpu(rhead->args.readdir.frag);
+       struct ceph_dentry_info *di;
+
+       if (le32_to_cpu(rinfo->head->op) == CEPH_MDS_OP_LSSNAP) {
+               snapdir = ceph_get_snapdir(parent->d_inode);
+               parent = d_find_alias(snapdir);
+               dout("readdir_prepopulate %d items under SNAPDIR dn %p\n",
+                    rinfo->dir_nr, parent);
+       } else {
+               dout("readdir_prepopulate %d items under dn %p\n",
+                    rinfo->dir_nr, parent);
+               if (rinfo->dir_dir)
+                       ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir);
+       }
+
+       for (i = 0; i < rinfo->dir_nr; i++) {
+               struct ceph_vino vino;
+
+               dname.name = rinfo->dir_dname[i];
+               dname.len = rinfo->dir_dname_len[i];
+               dname.hash = full_name_hash(dname.name, dname.len);
+
+               vino.ino = le64_to_cpu(rinfo->dir_in[i].in->ino);
+               vino.snap = le64_to_cpu(rinfo->dir_in[i].in->snapid);
+
+retry_lookup:
+               dn = d_lookup(parent, &dname);
+               dout("d_lookup on parent=%p name=%.*s got %p\n",
+                    parent, dname.len, dname.name, dn);
+
+               if (!dn) {
+                       dn = d_alloc(parent, &dname);
+                       dout("d_alloc %p '%.*s' = %p\n", parent,
+                            dname.len, dname.name, dn);
+                       if (dn == NULL) {
+                               dout("d_alloc badness\n");
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       err = ceph_init_dentry(dn);
+                       if (err < 0)
+                               goto out;
+               } else if (dn->d_inode &&
+                          (ceph_ino(dn->d_inode) != vino.ino ||
+                           ceph_snap(dn->d_inode) != vino.snap)) {
+                       dout(" dn %p points to wrong inode %p\n",
+                            dn, dn->d_inode);
+                       d_delete(dn);
+                       dput(dn);
+                       goto retry_lookup;
+               } else {
+                       /* reorder parent's d_subdirs */
+                       spin_lock(&dcache_lock);
+                       spin_lock(&dn->d_lock);
+                       list_move(&dn->d_u.d_child, &parent->d_subdirs);
+                       spin_unlock(&dn->d_lock);
+                       spin_unlock(&dcache_lock);
+               }
+
+               di = dn->d_fsdata;
+               di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset);
+
+               /* inode */
+               if (dn->d_inode) {
+                       in = dn->d_inode;
+               } else {
+                       in = ceph_get_inode(parent->d_sb, vino);
+                       if (in == NULL) {
+                               dout("new_inode badness\n");
+                               d_delete(dn);
+                               dput(dn);
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       dn = splice_dentry(dn, in, NULL);
+               }
+
+               if (fill_inode(in, &rinfo->dir_in[i], NULL, session,
+                              req->r_request_started, -1,
+                              &req->r_caps_reservation) < 0) {
+                       pr_err("fill_inode badness on %p\n", in);
+                       dput(dn);
+                       continue;
+               }
+               update_dentry_lease(dn, rinfo->dir_dlease[i],
+                                   req->r_session, req->r_request_started);
+               dput(dn);
+       }
+       req->r_did_prepopulate = true;
+
+out:
+       if (snapdir) {
+               iput(snapdir);
+               dput(parent);
+       }
+       dout("readdir_prepopulate done\n");
+       return err;
+}
+
+int ceph_inode_set_size(struct inode *inode, loff_t size)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int ret = 0;
+
+       spin_lock(&inode->i_lock);
+       dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size);
+       inode->i_size = size;
+       inode->i_blocks = (size + (1 << 9) - 1) >> 9;
+
+       /* tell the MDS if we are approaching max_size */
+       if ((size << 1) >= ci->i_max_size &&
+           (ci->i_reported_size << 1) < ci->i_max_size)
+               ret = 1;
+
+       spin_unlock(&inode->i_lock);
+       return ret;
+}
+
+/*
+ * Write back inode data in a worker thread.  (This can't be done
+ * in the message handler context.)
+ */
+void ceph_queue_writeback(struct inode *inode)
+{
+       if (queue_work(ceph_inode_to_client(inode)->wb_wq,
+                      &ceph_inode(inode)->i_wb_work)) {
+               dout("ceph_queue_writeback %p\n", inode);
+               igrab(inode);
+       } else {
+               dout("ceph_queue_writeback %p failed\n", inode);
+       }
+}
+
+static void ceph_writeback_work(struct work_struct *work)
+{
+       struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+                                                 i_wb_work);
+       struct inode *inode = &ci->vfs_inode;
+
+       dout("writeback %p\n", inode);
+       filemap_fdatawrite(&inode->i_data);
+       iput(inode);
+}
+
+/*
+ * queue an async invalidation
+ */
+void ceph_queue_invalidate(struct inode *inode)
+{
+       if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq,
+                      &ceph_inode(inode)->i_pg_inv_work)) {
+               dout("ceph_queue_invalidate %p\n", inode);
+               igrab(inode);
+       } else {
+               dout("ceph_queue_invalidate %p failed\n", inode);
+       }
+}
+
+/*
+ * invalidate any pages that are not dirty or under writeback.  this
+ * includes pages that are clean and mapped.
+ */
+static void ceph_invalidate_nondirty_pages(struct address_space *mapping)
+{
+       struct pagevec pvec;
+       pgoff_t next = 0;
+       int i;
+
+       pagevec_init(&pvec, 0);
+       while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
+                       pgoff_t index;
+                       int skip_page =
+                               (PageDirty(page) || PageWriteback(page));
+
+                       if (!skip_page)
+                               skip_page = !trylock_page(page);
+
+                       /*
+                        * We really shouldn't be looking at the ->index of an
+                        * unlocked page.  But we're not allowed to lock these
+                        * pages.  So we rely upon nobody altering the ->index
+                        * of this (pinned-by-us) page.
+                        */
+                       index = page->index;
+                       if (index > next)
+                               next = index;
+                       next++;
+
+                       if (skip_page)
+                               continue;
+
+                       generic_error_remove_page(mapping, page);
+                       unlock_page(page);
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+}
+
+/*
+ * Invalidate inode pages in a worker thread.  (This can't be done
+ * in the message handler context.)
+ */
+static void ceph_invalidate_work(struct work_struct *work)
+{
+       struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+                                                 i_pg_inv_work);
+       struct inode *inode = &ci->vfs_inode;
+       u32 orig_gen;
+       int check = 0;
+
+       spin_lock(&inode->i_lock);
+       dout("invalidate_pages %p gen %d revoking %d\n", inode,
+            ci->i_rdcache_gen, ci->i_rdcache_revoking);
+       if (ci->i_rdcache_gen == 0 ||
+           ci->i_rdcache_revoking != ci->i_rdcache_gen) {
+               BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen);
+               /* nevermind! */
+               ci->i_rdcache_revoking = 0;
+               spin_unlock(&inode->i_lock);
+               goto out;
+       }
+       orig_gen = ci->i_rdcache_gen;
+       spin_unlock(&inode->i_lock);
+
+       ceph_invalidate_nondirty_pages(inode->i_mapping);
+
+       spin_lock(&inode->i_lock);
+       if (orig_gen == ci->i_rdcache_gen) {
+               dout("invalidate_pages %p gen %d successful\n", inode,
+                    ci->i_rdcache_gen);
+               ci->i_rdcache_gen = 0;
+               ci->i_rdcache_revoking = 0;
+               check = 1;
+       } else {
+               dout("invalidate_pages %p gen %d raced, gen now %d\n",
+                    inode, orig_gen, ci->i_rdcache_gen);
+       }
+       spin_unlock(&inode->i_lock);
+
+       if (check)
+               ceph_check_caps(ci, 0, NULL);
+out:
+       iput(inode);
+}
+
+
+/*
+ * called by trunc_wq; take i_mutex ourselves
+ *
+ * We also truncate in a separate thread as well.
+ */
+static void ceph_vmtruncate_work(struct work_struct *work)
+{
+       struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+                                                 i_vmtruncate_work);
+       struct inode *inode = &ci->vfs_inode;
+
+       dout("vmtruncate_work %p\n", inode);
+       mutex_lock(&inode->i_mutex);
+       __ceph_do_pending_vmtruncate(inode);
+       mutex_unlock(&inode->i_mutex);
+       iput(inode);
+}
+
+/*
+ * Queue an async vmtruncate.  If we fail to queue work, we will handle
+ * the truncation the next time we call __ceph_do_pending_vmtruncate.
+ */
+void ceph_queue_vmtruncate(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       if (queue_work(ceph_client(inode->i_sb)->trunc_wq,
+                      &ci->i_vmtruncate_work)) {
+               dout("ceph_queue_vmtruncate %p\n", inode);
+               igrab(inode);
+       } else {
+               dout("ceph_queue_vmtruncate %p failed, pending=%d\n",
+                    inode, ci->i_truncate_pending);
+       }
+}
+
+/*
+ * called with i_mutex held.
+ *
+ * Make sure any pending truncation is applied before doing anything
+ * that may depend on it.
+ */
+void __ceph_do_pending_vmtruncate(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       u64 to;
+       int wrbuffer_refs, wake = 0;
+
+retry:
+       spin_lock(&inode->i_lock);
+       if (ci->i_truncate_pending == 0) {
+               dout("__do_pending_vmtruncate %p none pending\n", inode);
+               spin_unlock(&inode->i_lock);
+               return;
+       }
+
+       /*
+        * make sure any dirty snapped pages are flushed before we
+        * possibly truncate them.. so write AND block!
+        */
+       if (ci->i_wrbuffer_ref_head < ci->i_wrbuffer_ref) {
+               dout("__do_pending_vmtruncate %p flushing snaps first\n",
+                    inode);
+               spin_unlock(&inode->i_lock);
+               filemap_write_and_wait_range(&inode->i_data, 0,
+                                            inode->i_sb->s_maxbytes);
+               goto retry;
+       }
+
+       to = ci->i_truncate_size;
+       wrbuffer_refs = ci->i_wrbuffer_ref;
+       dout("__do_pending_vmtruncate %p (%d) to %lld\n", inode,
+            ci->i_truncate_pending, to);
+       spin_unlock(&inode->i_lock);
+
+       truncate_inode_pages(inode->i_mapping, to);
+
+       spin_lock(&inode->i_lock);
+       ci->i_truncate_pending--;
+       if (ci->i_truncate_pending == 0)
+               wake = 1;
+       spin_unlock(&inode->i_lock);
+
+       if (wrbuffer_refs == 0)
+               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+       if (wake)
+               wake_up(&ci->i_cap_wq);
+}
+
+
+/*
+ * symlinks
+ */
+static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       struct ceph_inode_info *ci = ceph_inode(dentry->d_inode);
+       nd_set_link(nd, ci->i_symlink);
+       return NULL;
+}
+
+static const struct inode_operations ceph_symlink_iops = {
+       .readlink = generic_readlink,
+       .follow_link = ceph_sym_follow_link,
+};
+
+/*
+ * setattr
+ */
+int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct inode *parent_inode = dentry->d_parent->d_inode;
+       const unsigned int ia_valid = attr->ia_valid;
+       struct ceph_mds_request *req;
+       struct ceph_mds_client *mdsc = &ceph_client(dentry->d_sb)->mdsc;
+       int issued;
+       int release = 0, dirtied = 0;
+       int mask = 0;
+       int err = 0;
+
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       __ceph_do_pending_vmtruncate(inode);
+
+       err = inode_change_ok(inode, attr);
+       if (err != 0)
+               return err;
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR,
+                                      USE_AUTH_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       spin_lock(&inode->i_lock);
+       issued = __ceph_caps_issued(ci, NULL);
+       dout("setattr %p issued %s\n", inode, ceph_cap_string(issued));
+
+       if (ia_valid & ATTR_UID) {
+               dout("setattr %p uid %d -> %d\n", inode,
+                    inode->i_uid, attr->ia_uid);
+               if (issued & CEPH_CAP_AUTH_EXCL) {
+                       inode->i_uid = attr->ia_uid;
+                       dirtied |= CEPH_CAP_AUTH_EXCL;
+               } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+                          attr->ia_uid != inode->i_uid) {
+                       req->r_args.setattr.uid = cpu_to_le32(attr->ia_uid);
+                       mask |= CEPH_SETATTR_UID;
+                       release |= CEPH_CAP_AUTH_SHARED;
+               }
+       }
+       if (ia_valid & ATTR_GID) {
+               dout("setattr %p gid %d -> %d\n", inode,
+                    inode->i_gid, attr->ia_gid);
+               if (issued & CEPH_CAP_AUTH_EXCL) {
+                       inode->i_gid = attr->ia_gid;
+                       dirtied |= CEPH_CAP_AUTH_EXCL;
+               } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+                          attr->ia_gid != inode->i_gid) {
+                       req->r_args.setattr.gid = cpu_to_le32(attr->ia_gid);
+                       mask |= CEPH_SETATTR_GID;
+                       release |= CEPH_CAP_AUTH_SHARED;
+               }
+       }
+       if (ia_valid & ATTR_MODE) {
+               dout("setattr %p mode 0%o -> 0%o\n", inode, inode->i_mode,
+                    attr->ia_mode);
+               if (issued & CEPH_CAP_AUTH_EXCL) {
+                       inode->i_mode = attr->ia_mode;
+                       dirtied |= CEPH_CAP_AUTH_EXCL;
+               } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+                          attr->ia_mode != inode->i_mode) {
+                       req->r_args.setattr.mode = cpu_to_le32(attr->ia_mode);
+                       mask |= CEPH_SETATTR_MODE;
+                       release |= CEPH_CAP_AUTH_SHARED;
+               }
+       }
+
+       if (ia_valid & ATTR_ATIME) {
+               dout("setattr %p atime %ld.%ld -> %ld.%ld\n", inode,
+                    inode->i_atime.tv_sec, inode->i_atime.tv_nsec,
+                    attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
+               if (issued & CEPH_CAP_FILE_EXCL) {
+                       ci->i_time_warp_seq++;
+                       inode->i_atime = attr->ia_atime;
+                       dirtied |= CEPH_CAP_FILE_EXCL;
+               } else if ((issued & CEPH_CAP_FILE_WR) &&
+                          timespec_compare(&inode->i_atime,
+                                           &attr->ia_atime) < 0) {
+                       inode->i_atime = attr->ia_atime;
+                       dirtied |= CEPH_CAP_FILE_WR;
+               } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+                          !timespec_equal(&inode->i_atime, &attr->ia_atime)) {
+                       ceph_encode_timespec(&req->r_args.setattr.atime,
+                                            &attr->ia_atime);
+                       mask |= CEPH_SETATTR_ATIME;
+                       release |= CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD |
+                               CEPH_CAP_FILE_WR;
+               }
+       }
+       if (ia_valid & ATTR_MTIME) {
+               dout("setattr %p mtime %ld.%ld -> %ld.%ld\n", inode,
+                    inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+                    attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
+               if (issued & CEPH_CAP_FILE_EXCL) {
+                       ci->i_time_warp_seq++;
+                       inode->i_mtime = attr->ia_mtime;
+                       dirtied |= CEPH_CAP_FILE_EXCL;
+               } else if ((issued & CEPH_CAP_FILE_WR) &&
+                          timespec_compare(&inode->i_mtime,
+                                           &attr->ia_mtime) < 0) {
+                       inode->i_mtime = attr->ia_mtime;
+                       dirtied |= CEPH_CAP_FILE_WR;
+               } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+                          !timespec_equal(&inode->i_mtime, &attr->ia_mtime)) {
+                       ceph_encode_timespec(&req->r_args.setattr.mtime,
+                                            &attr->ia_mtime);
+                       mask |= CEPH_SETATTR_MTIME;
+                       release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_RD |
+                               CEPH_CAP_FILE_WR;
+               }
+       }
+       if (ia_valid & ATTR_SIZE) {
+               dout("setattr %p size %lld -> %lld\n", inode,
+                    inode->i_size, attr->ia_size);
+               if (attr->ia_size > inode->i_sb->s_maxbytes) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               if ((issued & CEPH_CAP_FILE_EXCL) &&
+                   attr->ia_size > inode->i_size) {
+                       inode->i_size = attr->ia_size;
+                       inode->i_blocks =
+                               (attr->ia_size + (1 << 9) - 1) >> 9;
+                       inode->i_ctime = attr->ia_ctime;
+                       ci->i_reported_size = attr->ia_size;
+                       dirtied |= CEPH_CAP_FILE_EXCL;
+               } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+                          attr->ia_size != inode->i_size) {
+                       req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
+                       req->r_args.setattr.old_size =
+                               cpu_to_le64(inode->i_size);
+                       mask |= CEPH_SETATTR_SIZE;
+                       release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_RD |
+                               CEPH_CAP_FILE_WR;
+               }
+       }
+
+       /* these do nothing */
+       if (ia_valid & ATTR_CTIME) {
+               bool only = (ia_valid & (ATTR_SIZE|ATTR_MTIME|ATTR_ATIME|
+                                        ATTR_MODE|ATTR_UID|ATTR_GID)) == 0;
+               dout("setattr %p ctime %ld.%ld -> %ld.%ld (%s)\n", inode,
+                    inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+                    attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec,
+                    only ? "ctime only" : "ignored");
+               inode->i_ctime = attr->ia_ctime;
+               if (only) {
+                       /*
+                        * if kernel wants to dirty ctime but nothing else,
+                        * we need to choose a cap to dirty under, or do
+                        * a almost-no-op setattr
+                        */
+                       if (issued & CEPH_CAP_AUTH_EXCL)
+                               dirtied |= CEPH_CAP_AUTH_EXCL;
+                       else if (issued & CEPH_CAP_FILE_EXCL)
+                               dirtied |= CEPH_CAP_FILE_EXCL;
+                       else if (issued & CEPH_CAP_XATTR_EXCL)
+                               dirtied |= CEPH_CAP_XATTR_EXCL;
+                       else
+                               mask |= CEPH_SETATTR_CTIME;
+               }
+       }
+       if (ia_valid & ATTR_FILE)
+               dout("setattr %p ATTR_FILE ... hrm!\n", inode);
+
+       if (dirtied) {
+               __ceph_mark_dirty_caps(ci, dirtied);
+               inode->i_ctime = CURRENT_TIME;
+       }
+
+       release &= issued;
+       spin_unlock(&inode->i_lock);
+
+       if (mask) {
+               req->r_inode = igrab(inode);
+               req->r_inode_drop = release;
+               req->r_args.setattr.mask = cpu_to_le32(mask);
+               req->r_num_caps = 1;
+               err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       }
+       dout("setattr %p result=%d (%s locally, %d remote)\n", inode, err,
+            ceph_cap_string(dirtied), mask);
+
+       ceph_mdsc_put_request(req);
+       __ceph_do_pending_vmtruncate(inode);
+       return err;
+out:
+       spin_unlock(&inode->i_lock);
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
+/*
+ * Verify that we have a lease on the given mask.  If not,
+ * do a getattr against an mds.
+ */
+int ceph_do_getattr(struct inode *inode, int mask)
+{
+       struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req;
+       int err;
+
+       if (ceph_snap(inode) == CEPH_SNAPDIR) {
+               dout("do_getattr inode %p SNAPDIR\n", inode);
+               return 0;
+       }
+
+       dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask));
+       if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
+               return 0;
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       req->r_inode = igrab(inode);
+       req->r_num_caps = 1;
+       req->r_args.getattr.mask = cpu_to_le32(mask);
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+       ceph_mdsc_put_request(req);
+       dout("do_getattr result=%d\n", err);
+       return err;
+}
+
+
+/*
+ * Check inode permissions.  We verify we have a valid value for
+ * the AUTH cap, then call the generic handler.
+ */
+int ceph_permission(struct inode *inode, int mask)
+{
+       int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);
+
+       if (!err)
+               err = generic_permission(inode, mask, NULL);
+       return err;
+}
+
+/*
+ * Get all attributes.  Hopefully somedata we'll have a statlite()
+ * and can limit the fields we require to be accurate.
+ */
+int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
+                struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int err;
+
+       err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL);
+       if (!err) {
+               generic_fillattr(inode, stat);
+               stat->ino = inode->i_ino;
+               if (ceph_snap(inode) != CEPH_NOSNAP)
+                       stat->dev = ceph_snap(inode);
+               else
+                       stat->dev = 0;
+               if (S_ISDIR(inode->i_mode)) {
+                       stat->size = ci->i_rbytes;
+                       stat->blocks = 0;
+                       stat->blksize = 65536;
+               }
+       }
+       return err;
+}
diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c
new file mode 100644 (file)
index 0000000..8a5bcae
--- /dev/null
@@ -0,0 +1,160 @@
+#include <linux/in.h>
+
+#include "ioctl.h"
+#include "super.h"
+#include "ceph_debug.h"
+
+
+/*
+ * ioctls
+ */
+
+/*
+ * get and set the file layout
+ */
+static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
+{
+       struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
+       struct ceph_ioctl_layout l;
+       int err;
+
+       err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
+       if (!err) {
+               l.stripe_unit = ceph_file_layout_su(ci->i_layout);
+               l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
+               l.object_size = ceph_file_layout_object_size(ci->i_layout);
+               l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
+               l.preferred_osd =
+                       (s32)le32_to_cpu(ci->i_layout.fl_pg_preferred);
+               if (copy_to_user(arg, &l, sizeof(l)))
+                       return -EFAULT;
+       }
+
+       return err;
+}
+
+static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
+       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_request *req;
+       struct ceph_ioctl_layout l;
+       int err, i;
+
+       /* copy and validate */
+       if (copy_from_user(&l, arg, sizeof(l)))
+               return -EFAULT;
+
+       if ((l.object_size & ~PAGE_MASK) ||
+           (l.stripe_unit & ~PAGE_MASK) ||
+           !l.stripe_unit ||
+           (l.object_size &&
+            (unsigned)l.object_size % (unsigned)l.stripe_unit))
+               return -EINVAL;
+
+       /* make sure it's a valid data pool */
+       if (l.data_pool > 0) {
+               mutex_lock(&mdsc->mutex);
+               err = -EINVAL;
+               for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
+                       if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) {
+                               err = 0;
+                               break;
+                       }
+               mutex_unlock(&mdsc->mutex);
+               if (err)
+                       return err;
+       }
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
+                                      USE_AUTH_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       req->r_inode = igrab(inode);
+       req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
+
+       req->r_args.setlayout.layout.fl_stripe_unit =
+               cpu_to_le32(l.stripe_unit);
+       req->r_args.setlayout.layout.fl_stripe_count =
+               cpu_to_le32(l.stripe_count);
+       req->r_args.setlayout.layout.fl_object_size =
+               cpu_to_le32(l.object_size);
+       req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
+       req->r_args.setlayout.layout.fl_pg_preferred =
+               cpu_to_le32(l.preferred_osd);
+
+       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
+/*
+ * Return object name, size/offset information, and location (OSD
+ * number, network address) for a given file offset.
+ */
+static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
+{
+       struct ceph_ioctl_dataloc dl;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+       u64 len = 1, olen;
+       u64 tmp;
+       struct ceph_object_layout ol;
+       struct ceph_pg pgid;
+
+       /* copy and validate */
+       if (copy_from_user(&dl, arg, sizeof(dl)))
+               return -EFAULT;
+
+       down_read(&osdc->map_sem);
+       ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len,
+                                     &dl.object_no, &dl.object_offset, &olen);
+       dl.file_offset -= dl.object_offset;
+       dl.object_size = ceph_file_layout_object_size(ci->i_layout);
+       dl.block_size = ceph_file_layout_su(ci->i_layout);
+
+       /* block_offset = object_offset % block_size */
+       tmp = dl.object_offset;
+       dl.block_offset = do_div(tmp, dl.block_size);
+
+       snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
+                ceph_ino(inode), dl.object_no);
+       ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout,
+                               osdc->osdmap);
+
+       pgid = ol.ol_pgid;
+       dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
+       if (dl.osd >= 0) {
+               struct ceph_entity_addr *a =
+                       ceph_osd_addr(osdc->osdmap, dl.osd);
+               if (a)
+                       memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
+       } else {
+               memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
+       }
+       up_read(&osdc->map_sem);
+
+       /* send result back to user */
+       if (copy_to_user(arg, &dl, sizeof(dl)))
+               return -EFAULT;
+
+       return 0;
+}
+
+long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
+       switch (cmd) {
+       case CEPH_IOC_GET_LAYOUT:
+               return ceph_ioctl_get_layout(file, (void __user *)arg);
+
+       case CEPH_IOC_SET_LAYOUT:
+               return ceph_ioctl_set_layout(file, (void __user *)arg);
+
+       case CEPH_IOC_GET_DATALOC:
+               return ceph_ioctl_get_dataloc(file, (void __user *)arg);
+       }
+       return -ENOTTY;
+}
diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h
new file mode 100644 (file)
index 0000000..25e4f1a
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef FS_CEPH_IOCTL_H
+#define FS_CEPH_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define CEPH_IOCTL_MAGIC 0x97
+
+/* just use u64 to align sanely on all archs */
+struct ceph_ioctl_layout {
+       __u64 stripe_unit, stripe_count, object_size;
+       __u64 data_pool;
+       __s64 preferred_osd;
+};
+
+#define CEPH_IOC_GET_LAYOUT _IOR(CEPH_IOCTL_MAGIC, 1,          \
+                                  struct ceph_ioctl_layout)
+#define CEPH_IOC_SET_LAYOUT _IOW(CEPH_IOCTL_MAGIC, 2,          \
+                                  struct ceph_ioctl_layout)
+
+/*
+ * Extract identity, address of the OSD and object storing a given
+ * file offset.
+ */
+struct ceph_ioctl_dataloc {
+       __u64 file_offset;           /* in+out: file offset */
+       __u64 object_offset;         /* out: offset in object */
+       __u64 object_no;             /* out: object # */
+       __u64 object_size;           /* out: object size */
+       char object_name[64];        /* out: object name */
+       __u64 block_offset;          /* out: offset in block */
+       __u64 block_size;            /* out: block length */
+       __s64 osd;                   /* out: osd # */
+       struct sockaddr_storage osd_addr; /* out: osd address */
+};
+
+#define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3,        \
+                                  struct ceph_ioctl_dataloc)
+
+#endif
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
new file mode 100644 (file)
index 0000000..a260010
--- /dev/null
@@ -0,0 +1,3021 @@
+#include "ceph_debug.h"
+
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "mds_client.h"
+#include "mon_client.h"
+#include "super.h"
+#include "messenger.h"
+#include "decode.h"
+#include "auth.h"
+#include "pagelist.h"
+
+/*
+ * A cluster of MDS (metadata server) daemons is responsible for
+ * managing the file system namespace (the directory hierarchy and
+ * inodes) and for coordinating shared access to storage.  Metadata is
+ * partitioning hierarchically across a number of servers, and that
+ * partition varies over time as the cluster adjusts the distribution
+ * in order to balance load.
+ *
+ * The MDS client is primarily responsible to managing synchronous
+ * metadata requests for operations like open, unlink, and so forth.
+ * If there is a MDS failure, we find out about it when we (possibly
+ * request and) receive a new MDS map, and can resubmit affected
+ * requests.
+ *
+ * For the most part, though, we take advantage of a lossless
+ * communications channel to the MDS, and do not need to worry about
+ * timing out or resubmitting requests.
+ *
+ * We maintain a stateful "session" with each MDS we interact with.
+ * Within each session, we sent periodic heartbeat messages to ensure
+ * any capabilities or leases we have been issues remain valid.  If
+ * the session times out and goes stale, our leases and capabilities
+ * are no longer valid.
+ */
+
+static void __wake_requests(struct ceph_mds_client *mdsc,
+                           struct list_head *head);
+
+const static struct ceph_connection_operations mds_con_ops;
+
+
+/*
+ * mds reply parsing
+ */
+
+/*
+ * parse individual inode info
+ */
+static int parse_reply_info_in(void **p, void *end,
+                              struct ceph_mds_reply_info_in *info)
+{
+       int err = -EIO;
+
+       info->in = *p;
+       *p += sizeof(struct ceph_mds_reply_inode) +
+               sizeof(*info->in->fragtree.splits) *
+               le32_to_cpu(info->in->fragtree.nsplits);
+
+       ceph_decode_32_safe(p, end, info->symlink_len, bad);
+       ceph_decode_need(p, end, info->symlink_len, bad);
+       info->symlink = *p;
+       *p += info->symlink_len;
+
+       ceph_decode_32_safe(p, end, info->xattr_len, bad);
+       ceph_decode_need(p, end, info->xattr_len, bad);
+       info->xattr_data = *p;
+       *p += info->xattr_len;
+       return 0;
+bad:
+       return err;
+}
+
+/*
+ * parse a normal reply, which may contain a (dir+)dentry and/or a
+ * target inode.
+ */
+static int parse_reply_info_trace(void **p, void *end,
+                                 struct ceph_mds_reply_info_parsed *info)
+{
+       int err;
+
+       if (info->head->is_dentry) {
+               err = parse_reply_info_in(p, end, &info->diri);
+               if (err < 0)
+                       goto out_bad;
+
+               if (unlikely(*p + sizeof(*info->dirfrag) > end))
+                       goto bad;
+               info->dirfrag = *p;
+               *p += sizeof(*info->dirfrag) +
+                       sizeof(u32)*le32_to_cpu(info->dirfrag->ndist);
+               if (unlikely(*p > end))
+                       goto bad;
+
+               ceph_decode_32_safe(p, end, info->dname_len, bad);
+               ceph_decode_need(p, end, info->dname_len, bad);
+               info->dname = *p;
+               *p += info->dname_len;
+               info->dlease = *p;
+               *p += sizeof(*info->dlease);
+       }
+
+       if (info->head->is_target) {
+               err = parse_reply_info_in(p, end, &info->targeti);
+               if (err < 0)
+                       goto out_bad;
+       }
+
+       if (unlikely(*p != end))
+               goto bad;
+       return 0;
+
+bad:
+       err = -EIO;
+out_bad:
+       pr_err("problem parsing mds trace %d\n", err);
+       return err;
+}
+
+/*
+ * parse readdir results
+ */
+static int parse_reply_info_dir(void **p, void *end,
+                               struct ceph_mds_reply_info_parsed *info)
+{
+       u32 num, i = 0;
+       int err;
+
+       info->dir_dir = *p;
+       if (*p + sizeof(*info->dir_dir) > end)
+               goto bad;
+       *p += sizeof(*info->dir_dir) +
+               sizeof(u32)*le32_to_cpu(info->dir_dir->ndist);
+       if (*p > end)
+               goto bad;
+
+       ceph_decode_need(p, end, sizeof(num) + 2, bad);
+       num = ceph_decode_32(p);
+       info->dir_end = ceph_decode_8(p);
+       info->dir_complete = ceph_decode_8(p);
+       if (num == 0)
+               goto done;
+
+       /* alloc large array */
+       info->dir_nr = num;
+       info->dir_in = kcalloc(num, sizeof(*info->dir_in) +
+                              sizeof(*info->dir_dname) +
+                              sizeof(*info->dir_dname_len) +
+                              sizeof(*info->dir_dlease),
+                              GFP_NOFS);
+       if (info->dir_in == NULL) {
+               err = -ENOMEM;
+               goto out_bad;
+       }
+       info->dir_dname = (void *)(info->dir_in + num);
+       info->dir_dname_len = (void *)(info->dir_dname + num);
+       info->dir_dlease = (void *)(info->dir_dname_len + num);
+
+       while (num) {
+               /* dentry */
+               ceph_decode_need(p, end, sizeof(u32)*2, bad);
+               info->dir_dname_len[i] = ceph_decode_32(p);
+               ceph_decode_need(p, end, info->dir_dname_len[i], bad);
+               info->dir_dname[i] = *p;
+               *p += info->dir_dname_len[i];
+               dout("parsed dir dname '%.*s'\n", info->dir_dname_len[i],
+                    info->dir_dname[i]);
+               info->dir_dlease[i] = *p;
+               *p += sizeof(struct ceph_mds_reply_lease);
+
+               /* inode */
+               err = parse_reply_info_in(p, end, &info->dir_in[i]);
+               if (err < 0)
+                       goto out_bad;
+               i++;
+               num--;
+       }
+
+done:
+       if (*p != end)
+               goto bad;
+       return 0;
+
+bad:
+       err = -EIO;
+out_bad:
+       pr_err("problem parsing dir contents %d\n", err);
+       return err;
+}
+
+/*
+ * parse entire mds reply
+ */
+static int parse_reply_info(struct ceph_msg *msg,
+                           struct ceph_mds_reply_info_parsed *info)
+{
+       void *p, *end;
+       u32 len;
+       int err;
+
+       info->head = msg->front.iov_base;
+       p = msg->front.iov_base + sizeof(struct ceph_mds_reply_head);
+       end = p + msg->front.iov_len - sizeof(struct ceph_mds_reply_head);
+
+       /* trace */
+       ceph_decode_32_safe(&p, end, len, bad);
+       if (len > 0) {
+               err = parse_reply_info_trace(&p, p+len, info);
+               if (err < 0)
+                       goto out_bad;
+       }
+
+       /* dir content */
+       ceph_decode_32_safe(&p, end, len, bad);
+       if (len > 0) {
+               err = parse_reply_info_dir(&p, p+len, info);
+               if (err < 0)
+                       goto out_bad;
+       }
+
+       /* snap blob */
+       ceph_decode_32_safe(&p, end, len, bad);
+       info->snapblob_len = len;
+       info->snapblob = p;
+       p += len;
+
+       if (p != end)
+               goto bad;
+       return 0;
+
+bad:
+       err = -EIO;
+out_bad:
+       pr_err("mds parse_reply err %d\n", err);
+       return err;
+}
+
+static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info)
+{
+       kfree(info->dir_in);
+}
+
+
+/*
+ * sessions
+ */
+static const char *session_state_name(int s)
+{
+       switch (s) {
+       case CEPH_MDS_SESSION_NEW: return "new";
+       case CEPH_MDS_SESSION_OPENING: return "opening";
+       case CEPH_MDS_SESSION_OPEN: return "open";
+       case CEPH_MDS_SESSION_HUNG: return "hung";
+       case CEPH_MDS_SESSION_CLOSING: return "closing";
+       case CEPH_MDS_SESSION_RESTARTING: return "restarting";
+       case CEPH_MDS_SESSION_RECONNECTING: return "reconnecting";
+       default: return "???";
+       }
+}
+
+static struct ceph_mds_session *get_session(struct ceph_mds_session *s)
+{
+       if (atomic_inc_not_zero(&s->s_ref)) {
+               dout("mdsc get_session %p %d -> %d\n", s,
+                    atomic_read(&s->s_ref)-1, atomic_read(&s->s_ref));
+               return s;
+       } else {
+               dout("mdsc get_session %p 0 -- FAIL", s);
+               return NULL;
+       }
+}
+
+void ceph_put_mds_session(struct ceph_mds_session *s)
+{
+       dout("mdsc put_session %p %d -> %d\n", s,
+            atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1);
+       if (atomic_dec_and_test(&s->s_ref)) {
+               if (s->s_authorizer)
+                       s->s_mdsc->client->monc.auth->ops->destroy_authorizer(
+                               s->s_mdsc->client->monc.auth, s->s_authorizer);
+               kfree(s);
+       }
+}
+
+/*
+ * called under mdsc->mutex
+ */
+struct ceph_mds_session *__ceph_lookup_mds_session(struct ceph_mds_client *mdsc,
+                                                  int mds)
+{
+       struct ceph_mds_session *session;
+
+       if (mds >= mdsc->max_sessions || mdsc->sessions[mds] == NULL)
+               return NULL;
+       session = mdsc->sessions[mds];
+       dout("lookup_mds_session %p %d\n", session,
+            atomic_read(&session->s_ref));
+       get_session(session);
+       return session;
+}
+
+static bool __have_session(struct ceph_mds_client *mdsc, int mds)
+{
+       if (mds >= mdsc->max_sessions)
+               return false;
+       return mdsc->sessions[mds];
+}
+
+static int __verify_registered_session(struct ceph_mds_client *mdsc,
+                                      struct ceph_mds_session *s)
+{
+       if (s->s_mds >= mdsc->max_sessions ||
+           mdsc->sessions[s->s_mds] != s)
+               return -ENOENT;
+       return 0;
+}
+
+/*
+ * create+register a new session for given mds.
+ * called under mdsc->mutex.
+ */
+static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
+                                                int mds)
+{
+       struct ceph_mds_session *s;
+
+       s = kzalloc(sizeof(*s), GFP_NOFS);
+       s->s_mdsc = mdsc;
+       s->s_mds = mds;
+       s->s_state = CEPH_MDS_SESSION_NEW;
+       s->s_ttl = 0;
+       s->s_seq = 0;
+       mutex_init(&s->s_mutex);
+
+       ceph_con_init(mdsc->client->msgr, &s->s_con);
+       s->s_con.private = s;
+       s->s_con.ops = &mds_con_ops;
+       s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
+       s->s_con.peer_name.num = cpu_to_le64(mds);
+
+       spin_lock_init(&s->s_cap_lock);
+       s->s_cap_gen = 0;
+       s->s_cap_ttl = 0;
+       s->s_renew_requested = 0;
+       s->s_renew_seq = 0;
+       INIT_LIST_HEAD(&s->s_caps);
+       s->s_nr_caps = 0;
+       s->s_trim_caps = 0;
+       atomic_set(&s->s_ref, 1);
+       INIT_LIST_HEAD(&s->s_waiting);
+       INIT_LIST_HEAD(&s->s_unsafe);
+       s->s_num_cap_releases = 0;
+       s->s_cap_iterator = NULL;
+       INIT_LIST_HEAD(&s->s_cap_releases);
+       INIT_LIST_HEAD(&s->s_cap_releases_done);
+       INIT_LIST_HEAD(&s->s_cap_flushing);
+       INIT_LIST_HEAD(&s->s_cap_snaps_flushing);
+
+       dout("register_session mds%d\n", mds);
+       if (mds >= mdsc->max_sessions) {
+               int newmax = 1 << get_count_order(mds+1);
+               struct ceph_mds_session **sa;
+
+               dout("register_session realloc to %d\n", newmax);
+               sa = kcalloc(newmax, sizeof(void *), GFP_NOFS);
+               if (sa == NULL)
+                       goto fail_realloc;
+               if (mdsc->sessions) {
+                       memcpy(sa, mdsc->sessions,
+                              mdsc->max_sessions * sizeof(void *));
+                       kfree(mdsc->sessions);
+               }
+               mdsc->sessions = sa;
+               mdsc->max_sessions = newmax;
+       }
+       mdsc->sessions[mds] = s;
+       atomic_inc(&s->s_ref);  /* one ref to sessions[], one to caller */
+
+       ceph_con_open(&s->s_con, ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
+
+       return s;
+
+fail_realloc:
+       kfree(s);
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static void __unregister_session(struct ceph_mds_client *mdsc,
+                              struct ceph_mds_session *s)
+{
+       dout("__unregister_session mds%d %p\n", s->s_mds, s);
+       BUG_ON(mdsc->sessions[s->s_mds] != s);
+       mdsc->sessions[s->s_mds] = NULL;
+       ceph_con_close(&s->s_con);
+       ceph_put_mds_session(s);
+}
+
+/*
+ * drop session refs in request.
+ *
+ * should be last request ref, or hold mdsc->mutex
+ */
+static void put_request_session(struct ceph_mds_request *req)
+{
+       if (req->r_session) {
+               ceph_put_mds_session(req->r_session);
+               req->r_session = NULL;
+       }
+}
+
+void ceph_mdsc_release_request(struct kref *kref)
+{
+       struct ceph_mds_request *req = container_of(kref,
+                                                   struct ceph_mds_request,
+                                                   r_kref);
+       if (req->r_request)
+               ceph_msg_put(req->r_request);
+       if (req->r_reply) {
+               ceph_msg_put(req->r_reply);
+               destroy_reply_info(&req->r_reply_info);
+       }
+       if (req->r_inode) {
+               ceph_put_cap_refs(ceph_inode(req->r_inode),
+                                 CEPH_CAP_PIN);
+               iput(req->r_inode);
+       }
+       if (req->r_locked_dir)
+               ceph_put_cap_refs(ceph_inode(req->r_locked_dir),
+                                 CEPH_CAP_PIN);
+       if (req->r_target_inode)
+               iput(req->r_target_inode);
+       if (req->r_dentry)
+               dput(req->r_dentry);
+       if (req->r_old_dentry) {
+               ceph_put_cap_refs(
+                       ceph_inode(req->r_old_dentry->d_parent->d_inode),
+                       CEPH_CAP_PIN);
+               dput(req->r_old_dentry);
+       }
+       kfree(req->r_path1);
+       kfree(req->r_path2);
+       put_request_session(req);
+       ceph_unreserve_caps(&req->r_caps_reservation);
+       kfree(req);
+}
+
+/*
+ * lookup session, bump ref if found.
+ *
+ * called under mdsc->mutex.
+ */
+static struct ceph_mds_request *__lookup_request(struct ceph_mds_client *mdsc,
+                                            u64 tid)
+{
+       struct ceph_mds_request *req;
+       struct rb_node *n = mdsc->request_tree.rb_node;
+
+       while (n) {
+               req = rb_entry(n, struct ceph_mds_request, r_node);
+               if (tid < req->r_tid)
+                       n = n->rb_left;
+               else if (tid > req->r_tid)
+                       n = n->rb_right;
+               else {
+                       ceph_mdsc_get_request(req);
+                       return req;
+               }
+       }
+       return NULL;
+}
+
+static void __insert_request(struct ceph_mds_client *mdsc,
+                            struct ceph_mds_request *new)
+{
+       struct rb_node **p = &mdsc->request_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_mds_request *req = NULL;
+
+       while (*p) {
+               parent = *p;
+               req = rb_entry(parent, struct ceph_mds_request, r_node);
+               if (new->r_tid < req->r_tid)
+                       p = &(*p)->rb_left;
+               else if (new->r_tid > req->r_tid)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->r_node, parent, p);
+       rb_insert_color(&new->r_node, &mdsc->request_tree);
+}
+
+/*
+ * Register an in-flight request, and assign a tid.  Link to directory
+ * are modifying (if any).
+ *
+ * Called under mdsc->mutex.
+ */
+static void __register_request(struct ceph_mds_client *mdsc,
+                              struct ceph_mds_request *req,
+                              struct inode *dir)
+{
+       req->r_tid = ++mdsc->last_tid;
+       if (req->r_num_caps)
+               ceph_reserve_caps(&req->r_caps_reservation, req->r_num_caps);
+       dout("__register_request %p tid %lld\n", req, req->r_tid);
+       ceph_mdsc_get_request(req);
+       __insert_request(mdsc, req);
+
+       if (dir) {
+               struct ceph_inode_info *ci = ceph_inode(dir);
+
+               spin_lock(&ci->i_unsafe_lock);
+               req->r_unsafe_dir = dir;
+               list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
+               spin_unlock(&ci->i_unsafe_lock);
+       }
+}
+
+static void __unregister_request(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_request *req)
+{
+       dout("__unregister_request %p tid %lld\n", req, req->r_tid);
+       rb_erase(&req->r_node, &mdsc->request_tree);
+       ceph_mdsc_put_request(req);
+
+       if (req->r_unsafe_dir) {
+               struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir);
+
+               spin_lock(&ci->i_unsafe_lock);
+               list_del_init(&req->r_unsafe_dir_item);
+               spin_unlock(&ci->i_unsafe_lock);
+       }
+}
+
+/*
+ * Choose mds to send request to next.  If there is a hint set in the
+ * request (e.g., due to a prior forward hint from the mds), use that.
+ * Otherwise, consult frag tree and/or caps to identify the
+ * appropriate mds.  If all else fails, choose randomly.
+ *
+ * Called under mdsc->mutex.
+ */
+static int __choose_mds(struct ceph_mds_client *mdsc,
+                       struct ceph_mds_request *req)
+{
+       struct inode *inode;
+       struct ceph_inode_info *ci;
+       struct ceph_cap *cap;
+       int mode = req->r_direct_mode;
+       int mds = -1;
+       u32 hash = req->r_direct_hash;
+       bool is_hash = req->r_direct_is_hash;
+
+       /*
+        * is there a specific mds we should try?  ignore hint if we have
+        * no session and the mds is not up (active or recovering).
+        */
+       if (req->r_resend_mds >= 0 &&
+           (__have_session(mdsc, req->r_resend_mds) ||
+            ceph_mdsmap_get_state(mdsc->mdsmap, req->r_resend_mds) > 0)) {
+               dout("choose_mds using resend_mds mds%d\n",
+                    req->r_resend_mds);
+               return req->r_resend_mds;
+       }
+
+       if (mode == USE_RANDOM_MDS)
+               goto random;
+
+       inode = NULL;
+       if (req->r_inode) {
+               inode = req->r_inode;
+       } else if (req->r_dentry) {
+               if (req->r_dentry->d_inode) {
+                       inode = req->r_dentry->d_inode;
+               } else {
+                       inode = req->r_dentry->d_parent->d_inode;
+                       hash = req->r_dentry->d_name.hash;
+                       is_hash = true;
+               }
+       }
+       dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash,
+            (int)hash, mode);
+       if (!inode)
+               goto random;
+       ci = ceph_inode(inode);
+
+       if (is_hash && S_ISDIR(inode->i_mode)) {
+               struct ceph_inode_frag frag;
+               int found;
+
+               ceph_choose_frag(ci, hash, &frag, &found);
+               if (found) {
+                       if (mode == USE_ANY_MDS && frag.ndist > 0) {
+                               u8 r;
+
+                               /* choose a random replica */
+                               get_random_bytes(&r, 1);
+                               r %= frag.ndist;
+                               mds = frag.dist[r];
+                               dout("choose_mds %p %llx.%llx "
+                                    "frag %u mds%d (%d/%d)\n",
+                                    inode, ceph_vinop(inode),
+                                    frag.frag, frag.mds,
+                                    (int)r, frag.ndist);
+                               return mds;
+                       }
+
+                       /* since this file/dir wasn't known to be
+                        * replicated, then we want to look for the
+                        * authoritative mds. */
+                       mode = USE_AUTH_MDS;
+                       if (frag.mds >= 0) {
+                               /* choose auth mds */
+                               mds = frag.mds;
+                               dout("choose_mds %p %llx.%llx "
+                                    "frag %u mds%d (auth)\n",
+                                    inode, ceph_vinop(inode), frag.frag, mds);
+                               return mds;
+                       }
+               }
+       }
+
+       spin_lock(&inode->i_lock);
+       cap = NULL;
+       if (mode == USE_AUTH_MDS)
+               cap = ci->i_auth_cap;
+       if (!cap && !RB_EMPTY_ROOT(&ci->i_caps))
+               cap = rb_entry(rb_first(&ci->i_caps), struct ceph_cap, ci_node);
+       if (!cap) {
+               spin_unlock(&inode->i_lock);
+               goto random;
+       }
+       mds = cap->session->s_mds;
+       dout("choose_mds %p %llx.%llx mds%d (%scap %p)\n",
+            inode, ceph_vinop(inode), mds,
+            cap == ci->i_auth_cap ? "auth " : "", cap);
+       spin_unlock(&inode->i_lock);
+       return mds;
+
+random:
+       mds = ceph_mdsmap_get_random_mds(mdsc->mdsmap);
+       dout("choose_mds chose random mds%d\n", mds);
+       return mds;
+}
+
+
+/*
+ * session messages
+ */
+static struct ceph_msg *create_session_msg(u32 op, u64 seq)
+{
+       struct ceph_msg *msg;
+       struct ceph_mds_session_head *h;
+
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), 0, 0, NULL);
+       if (IS_ERR(msg)) {
+               pr_err("create_session_msg ENOMEM creating msg\n");
+               return ERR_PTR(PTR_ERR(msg));
+       }
+       h = msg->front.iov_base;
+       h->op = cpu_to_le32(op);
+       h->seq = cpu_to_le64(seq);
+       return msg;
+}
+
+/*
+ * send session open request.
+ *
+ * called under mdsc->mutex
+ */
+static int __open_session(struct ceph_mds_client *mdsc,
+                         struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+       int mstate;
+       int mds = session->s_mds;
+       int err = 0;
+
+       /* wait for mds to go active? */
+       mstate = ceph_mdsmap_get_state(mdsc->mdsmap, mds);
+       dout("open_session to mds%d (%s)\n", mds,
+            ceph_mds_state_name(mstate));
+       session->s_state = CEPH_MDS_SESSION_OPENING;
+       session->s_renew_requested = jiffies;
+
+       /* send connect message */
+       msg = create_session_msg(CEPH_SESSION_REQUEST_OPEN, session->s_seq);
+       if (IS_ERR(msg)) {
+               err = PTR_ERR(msg);
+               goto out;
+       }
+       ceph_con_send(&session->s_con, msg);
+
+out:
+       return 0;
+}
+
+/*
+ * session caps
+ */
+
+/*
+ * Free preallocated cap messages assigned to this session
+ */
+static void cleanup_cap_releases(struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+
+       spin_lock(&session->s_cap_lock);
+       while (!list_empty(&session->s_cap_releases)) {
+               msg = list_first_entry(&session->s_cap_releases,
+                                      struct ceph_msg, list_head);
+               list_del_init(&msg->list_head);
+               ceph_msg_put(msg);
+       }
+       while (!list_empty(&session->s_cap_releases_done)) {
+               msg = list_first_entry(&session->s_cap_releases_done,
+                                      struct ceph_msg, list_head);
+               list_del_init(&msg->list_head);
+               ceph_msg_put(msg);
+       }
+       spin_unlock(&session->s_cap_lock);
+}
+
+/*
+ * Helper to safely iterate over all caps associated with a session.
+ *
+ * caller must hold session s_mutex
+ */
+static int iterate_session_caps(struct ceph_mds_session *session,
+                                int (*cb)(struct inode *, struct ceph_cap *,
+                                           void *), void *arg)
+{
+       struct list_head *p;
+       struct ceph_cap *cap;
+       struct inode *inode, *last_inode = NULL;
+       struct ceph_cap *old_cap = NULL;
+       int ret;
+
+       dout("iterate_session_caps %p mds%d\n", session, session->s_mds);
+       spin_lock(&session->s_cap_lock);
+       p = session->s_caps.next;
+       while (p != &session->s_caps) {
+               cap = list_entry(p, struct ceph_cap, session_caps);
+               inode = igrab(&cap->ci->vfs_inode);
+               if (!inode) {
+                       p = p->next;
+                       continue;
+               }
+               session->s_cap_iterator = cap;
+               spin_unlock(&session->s_cap_lock);
+
+               if (last_inode) {
+                       iput(last_inode);
+                       last_inode = NULL;
+               }
+               if (old_cap) {
+                       ceph_put_cap(old_cap);
+                       old_cap = NULL;
+               }
+
+               ret = cb(inode, cap, arg);
+               last_inode = inode;
+
+               spin_lock(&session->s_cap_lock);
+               p = p->next;
+               if (cap->ci == NULL) {
+                       dout("iterate_session_caps  finishing cap %p removal\n",
+                            cap);
+                       BUG_ON(cap->session != session);
+                       list_del_init(&cap->session_caps);
+                       session->s_nr_caps--;
+                       cap->session = NULL;
+                       old_cap = cap;  /* put_cap it w/o locks held */
+               }
+               if (ret < 0)
+                       goto out;
+       }
+       ret = 0;
+out:
+       session->s_cap_iterator = NULL;
+       spin_unlock(&session->s_cap_lock);
+
+       if (last_inode)
+               iput(last_inode);
+       if (old_cap)
+               ceph_put_cap(old_cap);
+
+       return ret;
+}
+
+static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
+                                  void *arg)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       dout("removing cap %p, ci is %p, inode is %p\n",
+            cap, ci, &ci->vfs_inode);
+       ceph_remove_cap(cap);
+       return 0;
+}
+
+/*
+ * caller must hold session s_mutex
+ */
+static void remove_session_caps(struct ceph_mds_session *session)
+{
+       dout("remove_session_caps on %p\n", session);
+       iterate_session_caps(session, remove_session_caps_cb, NULL);
+       BUG_ON(session->s_nr_caps > 0);
+       cleanup_cap_releases(session);
+}
+
+/*
+ * wake up any threads waiting on this session's caps.  if the cap is
+ * old (didn't get renewed on the client reconnect), remove it now.
+ *
+ * caller must hold s_mutex.
+ */
+static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap,
+                             void *arg)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       wake_up(&ci->i_cap_wq);
+       if (arg) {
+               spin_lock(&inode->i_lock);
+               ci->i_wanted_max_size = 0;
+               ci->i_requested_max_size = 0;
+               spin_unlock(&inode->i_lock);
+       }
+       return 0;
+}
+
+static void wake_up_session_caps(struct ceph_mds_session *session,
+                                int reconnect)
+{
+       dout("wake_up_session_caps %p mds%d\n", session, session->s_mds);
+       iterate_session_caps(session, wake_up_session_cb,
+                            (void *)(unsigned long)reconnect);
+}
+
+/*
+ * Send periodic message to MDS renewing all currently held caps.  The
+ * ack will reset the expiration for all caps from this session.
+ *
+ * caller holds s_mutex
+ */
+static int send_renew_caps(struct ceph_mds_client *mdsc,
+                          struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+       int state;
+
+       if (time_after_eq(jiffies, session->s_cap_ttl) &&
+           time_after_eq(session->s_cap_ttl, session->s_renew_requested))
+               pr_info("mds%d caps stale\n", session->s_mds);
+
+       /* do not try to renew caps until a recovering mds has reconnected
+        * with its clients. */
+       state = ceph_mdsmap_get_state(mdsc->mdsmap, session->s_mds);
+       if (state < CEPH_MDS_STATE_RECONNECT) {
+               dout("send_renew_caps ignoring mds%d (%s)\n",
+                    session->s_mds, ceph_mds_state_name(state));
+               return 0;
+       }
+
+       dout("send_renew_caps to mds%d (%s)\n", session->s_mds,
+               ceph_mds_state_name(state));
+       session->s_renew_requested = jiffies;
+       msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS,
+                                ++session->s_renew_seq);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+       ceph_con_send(&session->s_con, msg);
+       return 0;
+}
+
+/*
+ * Note new cap ttl, and any transition from stale -> not stale (fresh?).
+ *
+ * Called under session->s_mutex
+ */
+static void renewed_caps(struct ceph_mds_client *mdsc,
+                        struct ceph_mds_session *session, int is_renew)
+{
+       int was_stale;
+       int wake = 0;
+
+       spin_lock(&session->s_cap_lock);
+       was_stale = is_renew && (session->s_cap_ttl == 0 ||
+                                time_after_eq(jiffies, session->s_cap_ttl));
+
+       session->s_cap_ttl = session->s_renew_requested +
+               mdsc->mdsmap->m_session_timeout*HZ;
+
+       if (was_stale) {
+               if (time_before(jiffies, session->s_cap_ttl)) {
+                       pr_info("mds%d caps renewed\n", session->s_mds);
+                       wake = 1;
+               } else {
+                       pr_info("mds%d caps still stale\n", session->s_mds);
+               }
+       }
+       dout("renewed_caps mds%d ttl now %lu, was %s, now %s\n",
+            session->s_mds, session->s_cap_ttl, was_stale ? "stale" : "fresh",
+            time_before(jiffies, session->s_cap_ttl) ? "stale" : "fresh");
+       spin_unlock(&session->s_cap_lock);
+
+       if (wake)
+               wake_up_session_caps(session, 0);
+}
+
+/*
+ * send a session close request
+ */
+static int request_close_session(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+       int err = 0;
+
+       dout("request_close_session mds%d state %s seq %lld\n",
+            session->s_mds, session_state_name(session->s_state),
+            session->s_seq);
+       msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq);
+       if (IS_ERR(msg))
+               err = PTR_ERR(msg);
+       else
+               ceph_con_send(&session->s_con, msg);
+       return err;
+}
+
+/*
+ * Called with s_mutex held.
+ */
+static int __close_session(struct ceph_mds_client *mdsc,
+                        struct ceph_mds_session *session)
+{
+       if (session->s_state >= CEPH_MDS_SESSION_CLOSING)
+               return 0;
+       session->s_state = CEPH_MDS_SESSION_CLOSING;
+       return request_close_session(mdsc, session);
+}
+
+/*
+ * Trim old(er) caps.
+ *
+ * Because we can't cache an inode without one or more caps, we do
+ * this indirectly: if a cap is unused, we prune its aliases, at which
+ * point the inode will hopefully get dropped to.
+ *
+ * Yes, this is a bit sloppy.  Our only real goal here is to respond to
+ * memory pressure from the MDS, though, so it needn't be perfect.
+ */
+static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
+{
+       struct ceph_mds_session *session = arg;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int used, oissued, mine;
+
+       if (session->s_trim_caps <= 0)
+               return -1;
+
+       spin_lock(&inode->i_lock);
+       mine = cap->issued | cap->implemented;
+       used = __ceph_caps_used(ci);
+       oissued = __ceph_caps_issued_other(ci, cap);
+
+       dout("trim_caps_cb %p cap %p mine %s oissued %s used %s\n",
+            inode, cap, ceph_cap_string(mine), ceph_cap_string(oissued),
+            ceph_cap_string(used));
+       if (ci->i_dirty_caps)
+               goto out;   /* dirty caps */
+       if ((used & ~oissued) & mine)
+               goto out;   /* we need these caps */
+
+       session->s_trim_caps--;
+       if (oissued) {
+               /* we aren't the only cap.. just remove us */
+               __ceph_remove_cap(cap);
+       } else {
+               /* try to drop referring dentries */
+               spin_unlock(&inode->i_lock);
+               d_prune_aliases(inode);
+               dout("trim_caps_cb %p cap %p  pruned, count now %d\n",
+                    inode, cap, atomic_read(&inode->i_count));
+               return 0;
+       }
+
+out:
+       spin_unlock(&inode->i_lock);
+       return 0;
+}
+
+/*
+ * Trim session cap count down to some max number.
+ */
+static int trim_caps(struct ceph_mds_client *mdsc,
+                    struct ceph_mds_session *session,
+                    int max_caps)
+{
+       int trim_caps = session->s_nr_caps - max_caps;
+
+       dout("trim_caps mds%d start: %d / %d, trim %d\n",
+            session->s_mds, session->s_nr_caps, max_caps, trim_caps);
+       if (trim_caps > 0) {
+               session->s_trim_caps = trim_caps;
+               iterate_session_caps(session, trim_caps_cb, session);
+               dout("trim_caps mds%d done: %d / %d, trimmed %d\n",
+                    session->s_mds, session->s_nr_caps, max_caps,
+                       trim_caps - session->s_trim_caps);
+               session->s_trim_caps = 0;
+       }
+       return 0;
+}
+
+/*
+ * Allocate cap_release messages.  If there is a partially full message
+ * in the queue, try to allocate enough to cover it's remainder, so that
+ * we can send it immediately.
+ *
+ * Called under s_mutex.
+ */
+static int add_cap_releases(struct ceph_mds_client *mdsc,
+                           struct ceph_mds_session *session,
+                           int extra)
+{
+       struct ceph_msg *msg;
+       struct ceph_mds_cap_release *head;
+       int err = -ENOMEM;
+
+       if (extra < 0)
+               extra = mdsc->client->mount_args->cap_release_safety;
+
+       spin_lock(&session->s_cap_lock);
+
+       if (!list_empty(&session->s_cap_releases)) {
+               msg = list_first_entry(&session->s_cap_releases,
+                                      struct ceph_msg,
+                                list_head);
+               head = msg->front.iov_base;
+               extra += CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num);
+       }
+
+       while (session->s_num_cap_releases < session->s_nr_caps + extra) {
+               spin_unlock(&session->s_cap_lock);
+               msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE,
+                                  0, 0, NULL);
+               if (!msg)
+                       goto out_unlocked;
+               dout("add_cap_releases %p msg %p now %d\n", session, msg,
+                    (int)msg->front.iov_len);
+               head = msg->front.iov_base;
+               head->num = cpu_to_le32(0);
+               msg->front.iov_len = sizeof(*head);
+               spin_lock(&session->s_cap_lock);
+               list_add(&msg->list_head, &session->s_cap_releases);
+               session->s_num_cap_releases += CEPH_CAPS_PER_RELEASE;
+       }
+
+       if (!list_empty(&session->s_cap_releases)) {
+               msg = list_first_entry(&session->s_cap_releases,
+                                      struct ceph_msg,
+                                      list_head);
+               head = msg->front.iov_base;
+               if (head->num) {
+                       dout(" queueing non-full %p (%d)\n", msg,
+                            le32_to_cpu(head->num));
+                       list_move_tail(&msg->list_head,
+                                     &session->s_cap_releases_done);
+                       session->s_num_cap_releases -=
+                               CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num);
+               }
+       }
+       err = 0;
+       spin_unlock(&session->s_cap_lock);
+out_unlocked:
+       return err;
+}
+
+/*
+ * flush all dirty inode data to disk.
+ *
+ * returns true if we've flushed through want_flush_seq
+ */
+static int check_cap_flush(struct ceph_mds_client *mdsc, u64 want_flush_seq)
+{
+       int mds, ret = 1;
+
+       dout("check_cap_flush want %lld\n", want_flush_seq);
+       mutex_lock(&mdsc->mutex);
+       for (mds = 0; ret && mds < mdsc->max_sessions; mds++) {
+               struct ceph_mds_session *session = mdsc->sessions[mds];
+
+               if (!session)
+                       continue;
+               get_session(session);
+               mutex_unlock(&mdsc->mutex);
+
+               mutex_lock(&session->s_mutex);
+               if (!list_empty(&session->s_cap_flushing)) {
+                       struct ceph_inode_info *ci =
+                               list_entry(session->s_cap_flushing.next,
+                                          struct ceph_inode_info,
+                                          i_flushing_item);
+                       struct inode *inode = &ci->vfs_inode;
+
+                       spin_lock(&inode->i_lock);
+                       if (ci->i_cap_flush_seq <= want_flush_seq) {
+                               dout("check_cap_flush still flushing %p "
+                                    "seq %lld <= %lld to mds%d\n", inode,
+                                    ci->i_cap_flush_seq, want_flush_seq,
+                                    session->s_mds);
+                               ret = 0;
+                       }
+                       spin_unlock(&inode->i_lock);
+               }
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+
+               if (!ret)
+                       return ret;
+               mutex_lock(&mdsc->mutex);
+       }
+
+       mutex_unlock(&mdsc->mutex);
+       dout("check_cap_flush ok, flushed thru %lld\n", want_flush_seq);
+       return ret;
+}
+
+/*
+ * called under s_mutex
+ */
+static void send_cap_releases(struct ceph_mds_client *mdsc,
+                      struct ceph_mds_session *session)
+{
+       struct ceph_msg *msg;
+
+       dout("send_cap_releases mds%d\n", session->s_mds);
+       while (1) {
+               spin_lock(&session->s_cap_lock);
+               if (list_empty(&session->s_cap_releases_done))
+                       break;
+               msg = list_first_entry(&session->s_cap_releases_done,
+                                struct ceph_msg, list_head);
+               list_del_init(&msg->list_head);
+               spin_unlock(&session->s_cap_lock);
+               msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+               dout("send_cap_releases mds%d %p\n", session->s_mds, msg);
+               ceph_con_send(&session->s_con, msg);
+       }
+       spin_unlock(&session->s_cap_lock);
+}
+
+/*
+ * requests
+ */
+
+/*
+ * Create an mds request.
+ */
+struct ceph_mds_request *
+ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
+{
+       struct ceph_mds_request *req = kzalloc(sizeof(*req), GFP_NOFS);
+
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->r_started = jiffies;
+       req->r_resend_mds = -1;
+       INIT_LIST_HEAD(&req->r_unsafe_dir_item);
+       req->r_fmode = -1;
+       kref_init(&req->r_kref);
+       INIT_LIST_HEAD(&req->r_wait);
+       init_completion(&req->r_completion);
+       init_completion(&req->r_safe_completion);
+       INIT_LIST_HEAD(&req->r_unsafe_item);
+
+       req->r_op = op;
+       req->r_direct_mode = mode;
+       return req;
+}
+
+/*
+ * return oldest (lowest) request, tid in request tree, 0 if none.
+ *
+ * called under mdsc->mutex.
+ */
+static struct ceph_mds_request *__get_oldest_req(struct ceph_mds_client *mdsc)
+{
+       if (RB_EMPTY_ROOT(&mdsc->request_tree))
+               return NULL;
+       return rb_entry(rb_first(&mdsc->request_tree),
+                       struct ceph_mds_request, r_node);
+}
+
+static u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
+{
+       struct ceph_mds_request *req = __get_oldest_req(mdsc);
+
+       if (req)
+               return req->r_tid;
+       return 0;
+}
+
+/*
+ * Build a dentry's path.  Allocate on heap; caller must kfree.  Based
+ * on build_path_from_dentry in fs/cifs/dir.c.
+ *
+ * If @stop_on_nosnap, generate path relative to the first non-snapped
+ * inode.
+ *
+ * Encode hidden .snap dirs as a double /, i.e.
+ *   foo/.snap/bar -> foo//bar
+ */
+char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
+                          int stop_on_nosnap)
+{
+       struct dentry *temp;
+       char *path;
+       int len, pos;
+
+       if (dentry == NULL)
+               return ERR_PTR(-EINVAL);
+
+retry:
+       len = 0;
+       for (temp = dentry; !IS_ROOT(temp);) {
+               struct inode *inode = temp->d_inode;
+               if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
+                       len++;  /* slash only */
+               else if (stop_on_nosnap && inode &&
+                        ceph_snap(inode) == CEPH_NOSNAP)
+                       break;
+               else
+                       len += 1 + temp->d_name.len;
+               temp = temp->d_parent;
+               if (temp == NULL) {
+                       pr_err("build_path_dentry corrupt dentry %p\n", dentry);
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+       if (len)
+               len--;  /* no leading '/' */
+
+       path = kmalloc(len+1, GFP_NOFS);
+       if (path == NULL)
+               return ERR_PTR(-ENOMEM);
+       pos = len;
+       path[pos] = 0;  /* trailing null */
+       for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
+               struct inode *inode = temp->d_inode;
+
+               if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
+                       dout("build_path_dentry path+%d: %p SNAPDIR\n",
+                            pos, temp);
+               } else if (stop_on_nosnap && inode &&
+                          ceph_snap(inode) == CEPH_NOSNAP) {
+                       break;
+               } else {
+                       pos -= temp->d_name.len;
+                       if (pos < 0)
+                               break;
+                       strncpy(path + pos, temp->d_name.name,
+                               temp->d_name.len);
+                       dout("build_path_dentry path+%d: %p '%.*s'\n",
+                            pos, temp, temp->d_name.len, path + pos);
+               }
+               if (pos)
+                       path[--pos] = '/';
+               temp = temp->d_parent;
+               if (temp == NULL) {
+                       pr_err("build_path_dentry corrupt dentry\n");
+                       kfree(path);
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+       if (pos != 0) {
+               pr_err("build_path_dentry did not end path lookup where "
+                      "expected, namelen is %d, pos is %d\n", len, pos);
+               /* presumably this is only possible if racing with a
+                  rename of one of the parent directories (we can not
+                  lock the dentries above us to prevent this, but
+                  retrying should be harmless) */
+               kfree(path);
+               goto retry;
+       }
+
+       *base = ceph_ino(temp->d_inode);
+       *plen = len;
+       dout("build_path_dentry on %p %d built %llx '%.*s'\n",
+            dentry, atomic_read(&dentry->d_count), *base, len, path);
+       return path;
+}
+
+static int build_dentry_path(struct dentry *dentry,
+                            const char **ppath, int *ppathlen, u64 *pino,
+                            int *pfreepath)
+{
+       char *path;
+
+       if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) {
+               *pino = ceph_ino(dentry->d_parent->d_inode);
+               *ppath = dentry->d_name.name;
+               *ppathlen = dentry->d_name.len;
+               return 0;
+       }
+       path = ceph_mdsc_build_path(dentry, ppathlen, pino, 1);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+       *ppath = path;
+       *pfreepath = 1;
+       return 0;
+}
+
+static int build_inode_path(struct inode *inode,
+                           const char **ppath, int *ppathlen, u64 *pino,
+                           int *pfreepath)
+{
+       struct dentry *dentry;
+       char *path;
+
+       if (ceph_snap(inode) == CEPH_NOSNAP) {
+               *pino = ceph_ino(inode);
+               *ppathlen = 0;
+               return 0;
+       }
+       dentry = d_find_alias(inode);
+       path = ceph_mdsc_build_path(dentry, ppathlen, pino, 1);
+       dput(dentry);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+       *ppath = path;
+       *pfreepath = 1;
+       return 0;
+}
+
+/*
+ * request arguments may be specified via an inode *, a dentry *, or
+ * an explicit ino+path.
+ */
+static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
+                                 const char *rpath, u64 rino,
+                                 const char **ppath, int *pathlen,
+                                 u64 *ino, int *freepath)
+{
+       int r = 0;
+
+       if (rinode) {
+               r = build_inode_path(rinode, ppath, pathlen, ino, freepath);
+               dout(" inode %p %llx.%llx\n", rinode, ceph_ino(rinode),
+                    ceph_snap(rinode));
+       } else if (rdentry) {
+               r = build_dentry_path(rdentry, ppath, pathlen, ino, freepath);
+               dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen,
+                    *ppath);
+       } else if (rpath) {
+               *ino = rino;
+               *ppath = rpath;
+               *pathlen = strlen(rpath);
+               dout(" path %.*s\n", *pathlen, rpath);
+       }
+
+       return r;
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
+                                              struct ceph_mds_request *req,
+                                              int mds)
+{
+       struct ceph_msg *msg;
+       struct ceph_mds_request_head *head;
+       const char *path1 = NULL;
+       const char *path2 = NULL;
+       u64 ino1 = 0, ino2 = 0;
+       int pathlen1 = 0, pathlen2 = 0;
+       int freepath1 = 0, freepath2 = 0;
+       int len;
+       u16 releases;
+       void *p, *end;
+       int ret;
+
+       ret = set_request_path_attr(req->r_inode, req->r_dentry,
+                             req->r_path1, req->r_ino1.ino,
+                             &path1, &pathlen1, &ino1, &freepath1);
+       if (ret < 0) {
+               msg = ERR_PTR(ret);
+               goto out;
+       }
+
+       ret = set_request_path_attr(NULL, req->r_old_dentry,
+                             req->r_path2, req->r_ino2.ino,
+                             &path2, &pathlen2, &ino2, &freepath2);
+       if (ret < 0) {
+               msg = ERR_PTR(ret);
+               goto out_free1;
+       }
+
+       len = sizeof(*head) +
+               pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64));
+
+       /* calculate (max) length for cap releases */
+       len += sizeof(struct ceph_mds_request_release) *
+               (!!req->r_inode_drop + !!req->r_dentry_drop +
+                !!req->r_old_inode_drop + !!req->r_old_dentry_drop);
+       if (req->r_dentry_drop)
+               len += req->r_dentry->d_name.len;
+       if (req->r_old_dentry_drop)
+               len += req->r_old_dentry->d_name.len;
+
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, 0, 0, NULL);
+       if (IS_ERR(msg))
+               goto out_free2;
+
+       msg->hdr.tid = cpu_to_le64(req->r_tid);
+
+       head = msg->front.iov_base;
+       p = msg->front.iov_base + sizeof(*head);
+       end = msg->front.iov_base + msg->front.iov_len;
+
+       head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch);
+       head->op = cpu_to_le32(req->r_op);
+       head->caller_uid = cpu_to_le32(current_fsuid());
+       head->caller_gid = cpu_to_le32(current_fsgid());
+       head->args = req->r_args;
+
+       ceph_encode_filepath(&p, end, ino1, path1);
+       ceph_encode_filepath(&p, end, ino2, path2);
+
+       /* cap releases */
+       releases = 0;
+       if (req->r_inode_drop)
+               releases += ceph_encode_inode_release(&p,
+                     req->r_inode ? req->r_inode : req->r_dentry->d_inode,
+                     mds, req->r_inode_drop, req->r_inode_unless, 0);
+       if (req->r_dentry_drop)
+               releases += ceph_encode_dentry_release(&p, req->r_dentry,
+                      mds, req->r_dentry_drop, req->r_dentry_unless);
+       if (req->r_old_dentry_drop)
+               releases += ceph_encode_dentry_release(&p, req->r_old_dentry,
+                      mds, req->r_old_dentry_drop, req->r_old_dentry_unless);
+       if (req->r_old_inode_drop)
+               releases += ceph_encode_inode_release(&p,
+                     req->r_old_dentry->d_inode,
+                     mds, req->r_old_inode_drop, req->r_old_inode_unless, 0);
+       head->num_releases = cpu_to_le16(releases);
+
+       BUG_ON(p > end);
+       msg->front.iov_len = p - msg->front.iov_base;
+       msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+
+       msg->pages = req->r_pages;
+       msg->nr_pages = req->r_num_pages;
+       msg->hdr.data_len = cpu_to_le32(req->r_data_len);
+       msg->hdr.data_off = cpu_to_le16(0);
+
+out_free2:
+       if (freepath2)
+               kfree((char *)path2);
+out_free1:
+       if (freepath1)
+               kfree((char *)path1);
+out:
+       return msg;
+}
+
+/*
+ * called under mdsc->mutex if error, under no mutex if
+ * success.
+ */
+static void complete_request(struct ceph_mds_client *mdsc,
+                            struct ceph_mds_request *req)
+{
+       if (req->r_callback)
+               req->r_callback(mdsc, req);
+       else
+               complete(&req->r_completion);
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static int __prepare_send_request(struct ceph_mds_client *mdsc,
+                                 struct ceph_mds_request *req,
+                                 int mds)
+{
+       struct ceph_mds_request_head *rhead;
+       struct ceph_msg *msg;
+       int flags = 0;
+
+       req->r_mds = mds;
+       req->r_attempts++;
+       dout("prepare_send_request %p tid %lld %s (attempt %d)\n", req,
+            req->r_tid, ceph_mds_op_name(req->r_op), req->r_attempts);
+
+       if (req->r_request) {
+               ceph_msg_put(req->r_request);
+               req->r_request = NULL;
+       }
+       msg = create_request_message(mdsc, req, mds);
+       if (IS_ERR(msg)) {
+               req->r_reply = ERR_PTR(PTR_ERR(msg));
+               complete_request(mdsc, req);
+               return -PTR_ERR(msg);
+       }
+       req->r_request = msg;
+
+       rhead = msg->front.iov_base;
+       rhead->oldest_client_tid = cpu_to_le64(__get_oldest_tid(mdsc));
+       if (req->r_got_unsafe)
+               flags |= CEPH_MDS_FLAG_REPLAY;
+       if (req->r_locked_dir)
+               flags |= CEPH_MDS_FLAG_WANT_DENTRY;
+       rhead->flags = cpu_to_le32(flags);
+       rhead->num_fwd = req->r_num_fwd;
+       rhead->num_retry = req->r_attempts - 1;
+
+       dout(" r_locked_dir = %p\n", req->r_locked_dir);
+
+       if (req->r_target_inode && req->r_got_unsafe)
+               rhead->ino = cpu_to_le64(ceph_ino(req->r_target_inode));
+       else
+               rhead->ino = 0;
+       return 0;
+}
+
+/*
+ * send request, or put it on the appropriate wait list.
+ */
+static int __do_request(struct ceph_mds_client *mdsc,
+                       struct ceph_mds_request *req)
+{
+       struct ceph_mds_session *session = NULL;
+       int mds = -1;
+       int err = -EAGAIN;
+
+       if (req->r_reply)
+               goto out;
+
+       if (req->r_timeout &&
+           time_after_eq(jiffies, req->r_started + req->r_timeout)) {
+               dout("do_request timed out\n");
+               err = -EIO;
+               goto finish;
+       }
+
+       mds = __choose_mds(mdsc, req);
+       if (mds < 0 ||
+           ceph_mdsmap_get_state(mdsc->mdsmap, mds) < CEPH_MDS_STATE_ACTIVE) {
+               dout("do_request no mds or not active, waiting for map\n");
+               list_add(&req->r_wait, &mdsc->waiting_for_map);
+               goto out;
+       }
+
+       /* get, open session */
+       session = __ceph_lookup_mds_session(mdsc, mds);
+       if (!session)
+               session = register_session(mdsc, mds);
+       dout("do_request mds%d session %p state %s\n", mds, session,
+            session_state_name(session->s_state));
+       if (session->s_state != CEPH_MDS_SESSION_OPEN &&
+           session->s_state != CEPH_MDS_SESSION_HUNG) {
+               if (session->s_state == CEPH_MDS_SESSION_NEW ||
+                   session->s_state == CEPH_MDS_SESSION_CLOSING)
+                       __open_session(mdsc, session);
+               list_add(&req->r_wait, &session->s_waiting);
+               goto out_session;
+       }
+
+       /* send request */
+       req->r_session = get_session(session);
+       req->r_resend_mds = -1;   /* forget any previous mds hint */
+
+       if (req->r_request_started == 0)   /* note request start time */
+               req->r_request_started = jiffies;
+
+       err = __prepare_send_request(mdsc, req, mds);
+       if (!err) {
+               ceph_msg_get(req->r_request);
+               ceph_con_send(&session->s_con, req->r_request);
+       }
+
+out_session:
+       ceph_put_mds_session(session);
+out:
+       return err;
+
+finish:
+       req->r_reply = ERR_PTR(err);
+       complete_request(mdsc, req);
+       goto out;
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static void __wake_requests(struct ceph_mds_client *mdsc,
+                           struct list_head *head)
+{
+       struct ceph_mds_request *req, *nreq;
+
+       list_for_each_entry_safe(req, nreq, head, r_wait) {
+               list_del_init(&req->r_wait);
+               __do_request(mdsc, req);
+       }
+}
+
+/*
+ * Wake up threads with requests pending for @mds, so that they can
+ * resubmit their requests to a possibly different mds.  If @all is set,
+ * wake up if their requests has been forwarded to @mds, too.
+ */
+static void kick_requests(struct ceph_mds_client *mdsc, int mds, int all)
+{
+       struct ceph_mds_request *req;
+       struct rb_node *p;
+
+       dout("kick_requests mds%d\n", mds);
+       for (p = rb_first(&mdsc->request_tree); p; p = rb_next(p)) {
+               req = rb_entry(p, struct ceph_mds_request, r_node);
+               if (req->r_got_unsafe)
+                       continue;
+               if (req->r_session &&
+                   req->r_session->s_mds == mds) {
+                       dout(" kicking tid %llu\n", req->r_tid);
+                       put_request_session(req);
+                       __do_request(mdsc, req);
+               }
+       }
+}
+
+void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+                             struct ceph_mds_request *req)
+{
+       dout("submit_request on %p\n", req);
+       mutex_lock(&mdsc->mutex);
+       __register_request(mdsc, req, NULL);
+       __do_request(mdsc, req);
+       mutex_unlock(&mdsc->mutex);
+}
+
+/*
+ * Synchrously perform an mds request.  Take care of all of the
+ * session setup, forwarding, retry details.
+ */
+int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
+                        struct inode *dir,
+                        struct ceph_mds_request *req)
+{
+       int err;
+
+       dout("do_request on %p\n", req);
+
+       /* take CAP_PIN refs for r_inode, r_locked_dir, r_old_dentry */
+       if (req->r_inode)
+               ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
+       if (req->r_locked_dir)
+               ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
+       if (req->r_old_dentry)
+               ceph_get_cap_refs(
+                       ceph_inode(req->r_old_dentry->d_parent->d_inode),
+                       CEPH_CAP_PIN);
+
+       /* issue */
+       mutex_lock(&mdsc->mutex);
+       __register_request(mdsc, req, dir);
+       __do_request(mdsc, req);
+
+       /* wait */
+       if (!req->r_reply) {
+               mutex_unlock(&mdsc->mutex);
+               if (req->r_timeout) {
+                       err = (long)wait_for_completion_interruptible_timeout(
+                               &req->r_completion, req->r_timeout);
+                       if (err == 0)
+                               req->r_reply = ERR_PTR(-EIO);
+                       else if (err < 0)
+                               req->r_reply = ERR_PTR(err);
+               } else {
+                        err = wait_for_completion_interruptible(
+                                &req->r_completion);
+                        if (err)
+                                req->r_reply = ERR_PTR(err);
+               }
+               mutex_lock(&mdsc->mutex);
+       }
+
+       if (IS_ERR(req->r_reply)) {
+               err = PTR_ERR(req->r_reply);
+               req->r_reply = NULL;
+
+               if (err == -ERESTARTSYS) {
+                       /* aborted */
+                       req->r_aborted = true;
+
+                       if (req->r_locked_dir &&
+                           (req->r_op & CEPH_MDS_OP_WRITE)) {
+                               struct ceph_inode_info *ci =
+                                       ceph_inode(req->r_locked_dir);
+
+                               dout("aborted, clearing I_COMPLETE on %p\n", 
+                                    req->r_locked_dir);
+                               spin_lock(&req->r_locked_dir->i_lock);
+                               ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+                               ci->i_release_count++;
+                               spin_unlock(&req->r_locked_dir->i_lock);
+                       }
+               } else {
+                       /* clean up this request */
+                       __unregister_request(mdsc, req);
+                       if (!list_empty(&req->r_unsafe_item))
+                               list_del_init(&req->r_unsafe_item);
+                       complete(&req->r_safe_completion);
+               }
+       } else if (req->r_err) {
+               err = req->r_err;
+       } else {
+               err = le32_to_cpu(req->r_reply_info.head->result);
+       }
+       mutex_unlock(&mdsc->mutex);
+
+       dout("do_request %p done, result %d\n", req, err);
+       return err;
+}
+
+/*
+ * Handle mds reply.
+ *
+ * We take the session mutex and parse and process the reply immediately.
+ * This preserves the logical ordering of replies, capabilities, etc., sent
+ * by the MDS as they are applied to our local cache.
+ */
+static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
+{
+       struct ceph_mds_client *mdsc = session->s_mdsc;
+       struct ceph_mds_request *req;
+       struct ceph_mds_reply_head *head = msg->front.iov_base;
+       struct ceph_mds_reply_info_parsed *rinfo;  /* parsed reply info */
+       u64 tid;
+       int err, result;
+       int mds = session->s_mds;
+
+       if (msg->front.iov_len < sizeof(*head)) {
+               pr_err("mdsc_handle_reply got corrupt (short) reply\n");
+               ceph_msg_dump(msg);
+               return;
+       }
+
+       /* get request, session */
+       tid = le64_to_cpu(msg->hdr.tid);
+       mutex_lock(&mdsc->mutex);
+       req = __lookup_request(mdsc, tid);
+       if (!req) {
+               dout("handle_reply on unknown tid %llu\n", tid);
+               mutex_unlock(&mdsc->mutex);
+               return;
+       }
+       dout("handle_reply %p\n", req);
+
+       /* correct session? */
+       if (!req->r_session && req->r_session != session) {
+               pr_err("mdsc_handle_reply got %llu on session mds%d"
+                      " not mds%d\n", tid, session->s_mds,
+                      req->r_session ? req->r_session->s_mds : -1);
+               mutex_unlock(&mdsc->mutex);
+               goto out;
+       }
+
+       /* dup? */
+       if ((req->r_got_unsafe && !head->safe) ||
+           (req->r_got_safe && head->safe)) {
+               pr_warning("got a dup %s reply on %llu from mds%d\n",
+                          head->safe ? "safe" : "unsafe", tid, mds);
+               mutex_unlock(&mdsc->mutex);
+               goto out;
+       }
+
+       result = le32_to_cpu(head->result);
+
+       /*
+        * Tolerate 2 consecutive ESTALEs from the same mds.
+        * FIXME: we should be looking at the cap migrate_seq.
+        */
+       if (result == -ESTALE) {
+               req->r_direct_mode = USE_AUTH_MDS;
+               req->r_num_stale++;
+               if (req->r_num_stale <= 2) {
+                       __do_request(mdsc, req);
+                       mutex_unlock(&mdsc->mutex);
+                       goto out;
+               }
+       } else {
+               req->r_num_stale = 0;
+       }
+
+       if (head->safe) {
+               req->r_got_safe = true;
+               __unregister_request(mdsc, req);
+               complete(&req->r_safe_completion);
+
+               if (req->r_got_unsafe) {
+                       /*
+                        * We already handled the unsafe response, now do the
+                        * cleanup.  No need to examine the response; the MDS
+                        * doesn't include any result info in the safe
+                        * response.  And even if it did, there is nothing
+                        * useful we could do with a revised return value.
+                        */
+                       dout("got safe reply %llu, mds%d\n", tid, mds);
+                       list_del_init(&req->r_unsafe_item);
+
+                       /* last unsafe request during umount? */
+                       if (mdsc->stopping && !__get_oldest_req(mdsc))
+                               complete(&mdsc->safe_umount_waiters);
+                       mutex_unlock(&mdsc->mutex);
+                       goto out;
+               }
+       }
+
+       BUG_ON(req->r_reply);
+
+       if (!head->safe) {
+               req->r_got_unsafe = true;
+               list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe);
+       }
+
+       dout("handle_reply tid %lld result %d\n", tid, result);
+       rinfo = &req->r_reply_info;
+       err = parse_reply_info(msg, rinfo);
+       mutex_unlock(&mdsc->mutex);
+
+       mutex_lock(&session->s_mutex);
+       if (err < 0) {
+               pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds);
+               ceph_msg_dump(msg);
+               goto out_err;
+       }
+
+       /* snap trace */
+       if (rinfo->snapblob_len) {
+               down_write(&mdsc->snap_rwsem);
+               ceph_update_snap_trace(mdsc, rinfo->snapblob,
+                              rinfo->snapblob + rinfo->snapblob_len,
+                              le32_to_cpu(head->op) == CEPH_MDS_OP_RMSNAP);
+               downgrade_write(&mdsc->snap_rwsem);
+       } else {
+               down_read(&mdsc->snap_rwsem);
+       }
+
+       /* insert trace into our cache */
+       err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
+       if (err == 0) {
+               if (result == 0 && rinfo->dir_nr)
+                       ceph_readdir_prepopulate(req, req->r_session);
+               ceph_unreserve_caps(&req->r_caps_reservation);
+       }
+
+       up_read(&mdsc->snap_rwsem);
+out_err:
+       if (err) {
+               req->r_err = err;
+       } else {
+               req->r_reply = msg;
+               ceph_msg_get(msg);
+       }
+
+       add_cap_releases(mdsc, req->r_session, -1);
+       mutex_unlock(&session->s_mutex);
+
+       /* kick calling process */
+       complete_request(mdsc, req);
+out:
+       ceph_mdsc_put_request(req);
+       return;
+}
+
+
+
+/*
+ * handle mds notification that our request has been forwarded.
+ */
+static void handle_forward(struct ceph_mds_client *mdsc,
+                          struct ceph_mds_session *session,
+                          struct ceph_msg *msg)
+{
+       struct ceph_mds_request *req;
+       u64 tid = le64_to_cpu(msg->hdr.tid);
+       u32 next_mds;
+       u32 fwd_seq;
+       int err = -EINVAL;
+       void *p = msg->front.iov_base;
+       void *end = p + msg->front.iov_len;
+
+       ceph_decode_need(&p, end, 2*sizeof(u32), bad);
+       next_mds = ceph_decode_32(&p);
+       fwd_seq = ceph_decode_32(&p);
+
+       mutex_lock(&mdsc->mutex);
+       req = __lookup_request(mdsc, tid);
+       if (!req) {
+               dout("forward %llu to mds%d - req dne\n", tid, next_mds);
+               goto out;  /* dup reply? */
+       }
+
+       if (fwd_seq <= req->r_num_fwd) {
+               dout("forward %llu to mds%d - old seq %d <= %d\n",
+                    tid, next_mds, req->r_num_fwd, fwd_seq);
+       } else {
+               /* resend. forward race not possible; mds would drop */
+               dout("forward %llu to mds%d (we resend)\n", tid, next_mds);
+               req->r_num_fwd = fwd_seq;
+               req->r_resend_mds = next_mds;
+               put_request_session(req);
+               __do_request(mdsc, req);
+       }
+       ceph_mdsc_put_request(req);
+out:
+       mutex_unlock(&mdsc->mutex);
+       return;
+
+bad:
+       pr_err("mdsc_handle_forward decode error err=%d\n", err);
+}
+
+/*
+ * handle a mds session control message
+ */
+static void handle_session(struct ceph_mds_session *session,
+                          struct ceph_msg *msg)
+{
+       struct ceph_mds_client *mdsc = session->s_mdsc;
+       u32 op;
+       u64 seq;
+       int mds = session->s_mds;
+       struct ceph_mds_session_head *h = msg->front.iov_base;
+       int wake = 0;
+
+       /* decode */
+       if (msg->front.iov_len != sizeof(*h))
+               goto bad;
+       op = le32_to_cpu(h->op);
+       seq = le64_to_cpu(h->seq);
+
+       mutex_lock(&mdsc->mutex);
+       if (op == CEPH_SESSION_CLOSE)
+               __unregister_session(mdsc, session);
+       /* FIXME: this ttl calculation is generous */
+       session->s_ttl = jiffies + HZ*mdsc->mdsmap->m_session_autoclose;
+       mutex_unlock(&mdsc->mutex);
+
+       mutex_lock(&session->s_mutex);
+
+       dout("handle_session mds%d %s %p state %s seq %llu\n",
+            mds, ceph_session_op_name(op), session,
+            session_state_name(session->s_state), seq);
+
+       if (session->s_state == CEPH_MDS_SESSION_HUNG) {
+               session->s_state = CEPH_MDS_SESSION_OPEN;
+               pr_info("mds%d came back\n", session->s_mds);
+       }
+
+       switch (op) {
+       case CEPH_SESSION_OPEN:
+               session->s_state = CEPH_MDS_SESSION_OPEN;
+               renewed_caps(mdsc, session, 0);
+               wake = 1;
+               if (mdsc->stopping)
+                       __close_session(mdsc, session);
+               break;
+
+       case CEPH_SESSION_RENEWCAPS:
+               if (session->s_renew_seq == seq)
+                       renewed_caps(mdsc, session, 1);
+               break;
+
+       case CEPH_SESSION_CLOSE:
+               remove_session_caps(session);
+               wake = 1; /* for good measure */
+               complete(&mdsc->session_close_waiters);
+               kick_requests(mdsc, mds, 0);      /* cur only */
+               break;
+
+       case CEPH_SESSION_STALE:
+               pr_info("mds%d caps went stale, renewing\n",
+                       session->s_mds);
+               spin_lock(&session->s_cap_lock);
+               session->s_cap_gen++;
+               session->s_cap_ttl = 0;
+               spin_unlock(&session->s_cap_lock);
+               send_renew_caps(mdsc, session);
+               break;
+
+       case CEPH_SESSION_RECALL_STATE:
+               trim_caps(mdsc, session, le32_to_cpu(h->max_caps));
+               break;
+
+       default:
+               pr_err("mdsc_handle_session bad op %d mds%d\n", op, mds);
+               WARN_ON(1);
+       }
+
+       mutex_unlock(&session->s_mutex);
+       if (wake) {
+               mutex_lock(&mdsc->mutex);
+               __wake_requests(mdsc, &session->s_waiting);
+               mutex_unlock(&mdsc->mutex);
+       }
+       return;
+
+bad:
+       pr_err("mdsc_handle_session corrupt message mds%d len %d\n", mds,
+              (int)msg->front.iov_len);
+       ceph_msg_dump(msg);
+       return;
+}
+
+
+/*
+ * called under session->mutex.
+ */
+static void replay_unsafe_requests(struct ceph_mds_client *mdsc,
+                                  struct ceph_mds_session *session)
+{
+       struct ceph_mds_request *req, *nreq;
+       int err;
+
+       dout("replay_unsafe_requests mds%d\n", session->s_mds);
+
+       mutex_lock(&mdsc->mutex);
+       list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) {
+               err = __prepare_send_request(mdsc, req, session->s_mds);
+               if (!err) {
+                       ceph_msg_get(req->r_request);
+                       ceph_con_send(&session->s_con, req->r_request);
+               }
+       }
+       mutex_unlock(&mdsc->mutex);
+}
+
+/*
+ * Encode information about a cap for a reconnect with the MDS.
+ */
+static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
+                         void *arg)
+{
+       struct ceph_mds_cap_reconnect rec;
+       struct ceph_inode_info *ci;
+       struct ceph_pagelist *pagelist = arg;
+       char *path;
+       int pathlen, err;
+       u64 pathbase;
+       struct dentry *dentry;
+
+       ci = cap->ci;
+
+       dout(" adding %p ino %llx.%llx cap %p %lld %s\n",
+            inode, ceph_vinop(inode), cap, cap->cap_id,
+            ceph_cap_string(cap->issued));
+       err = ceph_pagelist_encode_64(pagelist, ceph_ino(inode));
+       if (err)
+               return err;
+
+       dentry = d_find_alias(inode);
+       if (dentry) {
+               path = ceph_mdsc_build_path(dentry, &pathlen, &pathbase, 0);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       BUG_ON(err);
+               }
+       } else {
+               path = NULL;
+               pathlen = 0;
+       }
+       err = ceph_pagelist_encode_string(pagelist, path, pathlen);
+       if (err)
+               goto out;
+
+       spin_lock(&inode->i_lock);
+       cap->seq = 0;        /* reset cap seq */
+       cap->issue_seq = 0;  /* and issue_seq */
+       rec.cap_id = cpu_to_le64(cap->cap_id);
+       rec.pathbase = cpu_to_le64(pathbase);
+       rec.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
+       rec.issued = cpu_to_le32(cap->issued);
+       rec.size = cpu_to_le64(inode->i_size);
+       ceph_encode_timespec(&rec.mtime, &inode->i_mtime);
+       ceph_encode_timespec(&rec.atime, &inode->i_atime);
+       rec.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
+       spin_unlock(&inode->i_lock);
+
+       err = ceph_pagelist_append(pagelist, &rec, sizeof(rec));
+
+out:
+       kfree(path);
+       dput(dentry);
+       return err;
+}
+
+
+/*
+ * If an MDS fails and recovers, clients need to reconnect in order to
+ * reestablish shared state.  This includes all caps issued through
+ * this session _and_ the snap_realm hierarchy.  Because it's not
+ * clear which snap realms the mds cares about, we send everything we
+ * know about.. that ensures we'll then get any new info the
+ * recovering MDS might have.
+ *
+ * This is a relatively heavyweight operation, but it's rare.
+ *
+ * called with mdsc->mutex held.
+ */
+static void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds)
+{
+       struct ceph_mds_session *session = NULL;
+       struct ceph_msg *reply;
+       struct rb_node *p;
+       int err;
+       struct ceph_pagelist *pagelist;
+
+       pr_info("reconnect to recovering mds%d\n", mds);
+
+       pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
+       if (!pagelist)
+               goto fail_nopagelist;
+       ceph_pagelist_init(pagelist);
+
+       reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, 0, 0, 0, NULL);
+       if (IS_ERR(reply)) {
+               err = PTR_ERR(reply);
+               goto fail_nomsg;
+       }
+
+       /* find session */
+       session = __ceph_lookup_mds_session(mdsc, mds);
+       mutex_unlock(&mdsc->mutex);    /* drop lock for duration */
+
+       if (session) {
+               mutex_lock(&session->s_mutex);
+
+               session->s_state = CEPH_MDS_SESSION_RECONNECTING;
+               session->s_seq = 0;
+
+               ceph_con_open(&session->s_con,
+                             ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
+
+               /* replay unsafe requests */
+               replay_unsafe_requests(mdsc, session);
+       } else {
+               dout("no session for mds%d, will send short reconnect\n",
+                    mds);
+       }
+
+       down_read(&mdsc->snap_rwsem);
+
+       if (!session)
+               goto send;
+       dout("session %p state %s\n", session,
+            session_state_name(session->s_state));
+
+       /* traverse this session's caps */
+       err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps);
+       if (err)
+               goto fail;
+       err = iterate_session_caps(session, encode_caps_cb, pagelist);
+       if (err < 0)
+               goto out;
+
+       /*
+        * snaprealms.  we provide mds with the ino, seq (version), and
+        * parent for all of our realms.  If the mds has any newer info,
+        * it will tell us.
+        */
+       for (p = rb_first(&mdsc->snap_realms); p; p = rb_next(p)) {
+               struct ceph_snap_realm *realm =
+                       rb_entry(p, struct ceph_snap_realm, node);
+               struct ceph_mds_snaprealm_reconnect sr_rec;
+
+               dout(" adding snap realm %llx seq %lld parent %llx\n",
+                    realm->ino, realm->seq, realm->parent_ino);
+               sr_rec.ino = cpu_to_le64(realm->ino);
+               sr_rec.seq = cpu_to_le64(realm->seq);
+               sr_rec.parent = cpu_to_le64(realm->parent_ino);
+               err = ceph_pagelist_append(pagelist, &sr_rec, sizeof(sr_rec));
+               if (err)
+                       goto fail;
+       }
+
+send:
+       reply->pagelist = pagelist;
+       reply->hdr.data_len = cpu_to_le32(pagelist->length);
+       reply->nr_pages = calc_pages_for(0, pagelist->length);
+       ceph_con_send(&session->s_con, reply);
+
+       if (session) {
+               session->s_state = CEPH_MDS_SESSION_OPEN;
+               __wake_requests(mdsc, &session->s_waiting);
+       }
+
+out:
+       up_read(&mdsc->snap_rwsem);
+       if (session) {
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+       }
+       mutex_lock(&mdsc->mutex);
+       return;
+
+fail:
+       ceph_msg_put(reply);
+fail_nomsg:
+       ceph_pagelist_release(pagelist);
+       kfree(pagelist);
+fail_nopagelist:
+       pr_err("ENOMEM preparing reconnect for mds%d\n", mds);
+       goto out;
+}
+
+
+/*
+ * compare old and new mdsmaps, kicking requests
+ * and closing out old connections as necessary
+ *
+ * called under mdsc->mutex.
+ */
+static void check_new_map(struct ceph_mds_client *mdsc,
+                         struct ceph_mdsmap *newmap,
+                         struct ceph_mdsmap *oldmap)
+{
+       int i;
+       int oldstate, newstate;
+       struct ceph_mds_session *s;
+
+       dout("check_new_map new %u old %u\n",
+            newmap->m_epoch, oldmap->m_epoch);
+
+       for (i = 0; i < oldmap->m_max_mds && i < mdsc->max_sessions; i++) {
+               if (mdsc->sessions[i] == NULL)
+                       continue;
+               s = mdsc->sessions[i];
+               oldstate = ceph_mdsmap_get_state(oldmap, i);
+               newstate = ceph_mdsmap_get_state(newmap, i);
+
+               dout("check_new_map mds%d state %s -> %s (session %s)\n",
+                    i, ceph_mds_state_name(oldstate),
+                    ceph_mds_state_name(newstate),
+                    session_state_name(s->s_state));
+
+               if (memcmp(ceph_mdsmap_get_addr(oldmap, i),
+                          ceph_mdsmap_get_addr(newmap, i),
+                          sizeof(struct ceph_entity_addr))) {
+                       if (s->s_state == CEPH_MDS_SESSION_OPENING) {
+                               /* the session never opened, just close it
+                                * out now */
+                               __wake_requests(mdsc, &s->s_waiting);
+                               __unregister_session(mdsc, s);
+                       } else {
+                               /* just close it */
+                               mutex_unlock(&mdsc->mutex);
+                               mutex_lock(&s->s_mutex);
+                               mutex_lock(&mdsc->mutex);
+                               ceph_con_close(&s->s_con);
+                               mutex_unlock(&s->s_mutex);
+                               s->s_state = CEPH_MDS_SESSION_RESTARTING;
+                       }
+
+                       /* kick any requests waiting on the recovering mds */
+                       kick_requests(mdsc, i, 1);
+               } else if (oldstate == newstate) {
+                       continue;  /* nothing new with this mds */
+               }
+
+               /*
+                * send reconnect?
+                */
+               if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
+                   newstate >= CEPH_MDS_STATE_RECONNECT)
+                       send_mds_reconnect(mdsc, i);
+
+               /*
+                * kick requests on any mds that has gone active.
+                *
+                * kick requests on cur or forwarder: we may have sent
+                * the request to mds1, mds1 told us it forwarded it
+                * to mds2, but then we learn mds1 failed and can't be
+                * sure it successfully forwarded our request before
+                * it died.
+                */
+               if (oldstate < CEPH_MDS_STATE_ACTIVE &&
+                   newstate >= CEPH_MDS_STATE_ACTIVE) {
+                       pr_info("mds%d reconnect completed\n", s->s_mds);
+                       kick_requests(mdsc, i, 1);
+                       ceph_kick_flushing_caps(mdsc, s);
+                       wake_up_session_caps(s, 1);
+               }
+       }
+}
+
+
+
+/*
+ * leases
+ */
+
+/*
+ * caller must hold session s_mutex, dentry->d_lock
+ */
+void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry)
+{
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+
+       ceph_put_mds_session(di->lease_session);
+       di->lease_session = NULL;
+}
+
+static void handle_lease(struct ceph_mds_client *mdsc,
+                        struct ceph_mds_session *session,
+                        struct ceph_msg *msg)
+{
+       struct super_block *sb = mdsc->client->sb;
+       struct inode *inode;
+       struct ceph_inode_info *ci;
+       struct dentry *parent, *dentry;
+       struct ceph_dentry_info *di;
+       int mds = session->s_mds;
+       struct ceph_mds_lease *h = msg->front.iov_base;
+       struct ceph_vino vino;
+       int mask;
+       struct qstr dname;
+       int release = 0;
+
+       dout("handle_lease from mds%d\n", mds);
+
+       /* decode */
+       if (msg->front.iov_len < sizeof(*h) + sizeof(u32))
+               goto bad;
+       vino.ino = le64_to_cpu(h->ino);
+       vino.snap = CEPH_NOSNAP;
+       mask = le16_to_cpu(h->mask);
+       dname.name = (void *)h + sizeof(*h) + sizeof(u32);
+       dname.len = msg->front.iov_len - sizeof(*h) - sizeof(u32);
+       if (dname.len != get_unaligned_le32(h+1))
+               goto bad;
+
+       mutex_lock(&session->s_mutex);
+       session->s_seq++;
+
+       /* lookup inode */
+       inode = ceph_find_inode(sb, vino);
+       dout("handle_lease '%s', mask %d, ino %llx %p\n",
+            ceph_lease_op_name(h->action), mask, vino.ino, inode);
+       if (inode == NULL) {
+               dout("handle_lease no inode %llx\n", vino.ino);
+               goto release;
+       }
+       ci = ceph_inode(inode);
+
+       /* dentry */
+       parent = d_find_alias(inode);
+       if (!parent) {
+               dout("no parent dentry on inode %p\n", inode);
+               WARN_ON(1);
+               goto release;  /* hrm... */
+       }
+       dname.hash = full_name_hash(dname.name, dname.len);
+       dentry = d_lookup(parent, &dname);
+       dput(parent);
+       if (!dentry)
+               goto release;
+
+       spin_lock(&dentry->d_lock);
+       di = ceph_dentry(dentry);
+       switch (h->action) {
+       case CEPH_MDS_LEASE_REVOKE:
+               if (di && di->lease_session == session) {
+                       h->seq = cpu_to_le32(di->lease_seq);
+                       __ceph_mdsc_drop_dentry_lease(dentry);
+               }
+               release = 1;
+               break;
+
+       case CEPH_MDS_LEASE_RENEW:
+               if (di && di->lease_session == session &&
+                   di->lease_gen == session->s_cap_gen &&
+                   di->lease_renew_from &&
+                   di->lease_renew_after == 0) {
+                       unsigned long duration =
+                               le32_to_cpu(h->duration_ms) * HZ / 1000;
+
+                       di->lease_seq = le32_to_cpu(h->seq);
+                       dentry->d_time = di->lease_renew_from + duration;
+                       di->lease_renew_after = di->lease_renew_from +
+                               (duration >> 1);
+                       di->lease_renew_from = 0;
+               }
+               break;
+       }
+       spin_unlock(&dentry->d_lock);
+       dput(dentry);
+
+       if (!release)
+               goto out;
+
+release:
+       /* let's just reuse the same message */
+       h->action = CEPH_MDS_LEASE_REVOKE_ACK;
+       ceph_msg_get(msg);
+       ceph_con_send(&session->s_con, msg);
+
+out:
+       iput(inode);
+       mutex_unlock(&session->s_mutex);
+       return;
+
+bad:
+       pr_err("corrupt lease message\n");
+       ceph_msg_dump(msg);
+}
+
+void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
+                             struct inode *inode,
+                             struct dentry *dentry, char action,
+                             u32 seq)
+{
+       struct ceph_msg *msg;
+       struct ceph_mds_lease *lease;
+       int len = sizeof(*lease) + sizeof(u32);
+       int dnamelen = 0;
+
+       dout("lease_send_msg inode %p dentry %p %s to mds%d\n",
+            inode, dentry, ceph_lease_op_name(action), session->s_mds);
+       dnamelen = dentry->d_name.len;
+       len += dnamelen;
+
+       msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, 0, 0, NULL);
+       if (IS_ERR(msg))
+               return;
+       lease = msg->front.iov_base;
+       lease->action = action;
+       lease->mask = cpu_to_le16(CEPH_LOCK_DN);
+       lease->ino = cpu_to_le64(ceph_vino(inode).ino);
+       lease->first = lease->last = cpu_to_le64(ceph_vino(inode).snap);
+       lease->seq = cpu_to_le32(seq);
+       put_unaligned_le32(dnamelen, lease + 1);
+       memcpy((void *)(lease + 1) + 4, dentry->d_name.name, dnamelen);
+
+       /*
+        * if this is a preemptive lease RELEASE, no need to
+        * flush request stream, since the actual request will
+        * soon follow.
+        */
+       msg->more_to_follow = (action == CEPH_MDS_LEASE_RELEASE);
+
+       ceph_con_send(&session->s_con, msg);
+}
+
+/*
+ * Preemptively release a lease we expect to invalidate anyway.
+ * Pass @inode always, @dentry is optional.
+ */
+void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc, struct inode *inode,
+                            struct dentry *dentry, int mask)
+{
+       struct ceph_dentry_info *di;
+       struct ceph_mds_session *session;
+       u32 seq;
+
+       BUG_ON(inode == NULL);
+       BUG_ON(dentry == NULL);
+       BUG_ON(mask != CEPH_LOCK_DN);
+
+       /* is dentry lease valid? */
+       spin_lock(&dentry->d_lock);
+       di = ceph_dentry(dentry);
+       if (!di || !di->lease_session ||
+           di->lease_session->s_mds < 0 ||
+           di->lease_gen != di->lease_session->s_cap_gen ||
+           !time_before(jiffies, dentry->d_time)) {
+               dout("lease_release inode %p dentry %p -- "
+                    "no lease on %d\n",
+                    inode, dentry, mask);
+               spin_unlock(&dentry->d_lock);
+               return;
+       }
+
+       /* we do have a lease on this dentry; note mds and seq */
+       session = ceph_get_mds_session(di->lease_session);
+       seq = di->lease_seq;
+       __ceph_mdsc_drop_dentry_lease(dentry);
+       spin_unlock(&dentry->d_lock);
+
+       dout("lease_release inode %p dentry %p mask %d to mds%d\n",
+            inode, dentry, mask, session->s_mds);
+       ceph_mdsc_lease_send_msg(session, inode, dentry,
+                                CEPH_MDS_LEASE_RELEASE, seq);
+       ceph_put_mds_session(session);
+}
+
+/*
+ * drop all leases (and dentry refs) in preparation for umount
+ */
+static void drop_leases(struct ceph_mds_client *mdsc)
+{
+       int i;
+
+       dout("drop_leases\n");
+       mutex_lock(&mdsc->mutex);
+       for (i = 0; i < mdsc->max_sessions; i++) {
+               struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i);
+               if (!s)
+                       continue;
+               mutex_unlock(&mdsc->mutex);
+               mutex_lock(&s->s_mutex);
+               mutex_unlock(&s->s_mutex);
+               ceph_put_mds_session(s);
+               mutex_lock(&mdsc->mutex);
+       }
+       mutex_unlock(&mdsc->mutex);
+}
+
+
+
+/*
+ * delayed work -- periodically trim expired leases, renew caps with mds
+ */
+static void schedule_delayed(struct ceph_mds_client *mdsc)
+{
+       int delay = 5;
+       unsigned hz = round_jiffies_relative(HZ * delay);
+       schedule_delayed_work(&mdsc->delayed_work, hz);
+}
+
+static void delayed_work(struct work_struct *work)
+{
+       int i;
+       struct ceph_mds_client *mdsc =
+               container_of(work, struct ceph_mds_client, delayed_work.work);
+       int renew_interval;
+       int renew_caps;
+
+       dout("mdsc delayed_work\n");
+       ceph_check_delayed_caps(mdsc);
+
+       mutex_lock(&mdsc->mutex);
+       renew_interval = mdsc->mdsmap->m_session_timeout >> 2;
+       renew_caps = time_after_eq(jiffies, HZ*renew_interval +
+                                  mdsc->last_renew_caps);
+       if (renew_caps)
+               mdsc->last_renew_caps = jiffies;
+
+       for (i = 0; i < mdsc->max_sessions; i++) {
+               struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i);
+               if (s == NULL)
+                       continue;
+               if (s->s_state == CEPH_MDS_SESSION_CLOSING) {
+                       dout("resending session close request for mds%d\n",
+                            s->s_mds);
+                       request_close_session(mdsc, s);
+                       ceph_put_mds_session(s);
+                       continue;
+               }
+               if (s->s_ttl && time_after(jiffies, s->s_ttl)) {
+                       if (s->s_state == CEPH_MDS_SESSION_OPEN) {
+                               s->s_state = CEPH_MDS_SESSION_HUNG;
+                               pr_info("mds%d hung\n", s->s_mds);
+                       }
+               }
+               if (s->s_state < CEPH_MDS_SESSION_OPEN) {
+                       /* this mds is failed or recovering, just wait */
+                       ceph_put_mds_session(s);
+                       continue;
+               }
+               mutex_unlock(&mdsc->mutex);
+
+               mutex_lock(&s->s_mutex);
+               if (renew_caps)
+                       send_renew_caps(mdsc, s);
+               else
+                       ceph_con_keepalive(&s->s_con);
+               add_cap_releases(mdsc, s, -1);
+               send_cap_releases(mdsc, s);
+               mutex_unlock(&s->s_mutex);
+               ceph_put_mds_session(s);
+
+               mutex_lock(&mdsc->mutex);
+       }
+       mutex_unlock(&mdsc->mutex);
+
+       schedule_delayed(mdsc);
+}
+
+
+int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
+{
+       mdsc->client = client;
+       mutex_init(&mdsc->mutex);
+       mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
+       init_completion(&mdsc->safe_umount_waiters);
+       init_completion(&mdsc->session_close_waiters);
+       INIT_LIST_HEAD(&mdsc->waiting_for_map);
+       mdsc->sessions = NULL;
+       mdsc->max_sessions = 0;
+       mdsc->stopping = 0;
+       init_rwsem(&mdsc->snap_rwsem);
+       mdsc->snap_realms = RB_ROOT;
+       INIT_LIST_HEAD(&mdsc->snap_empty);
+       spin_lock_init(&mdsc->snap_empty_lock);
+       mdsc->last_tid = 0;
+       mdsc->request_tree = RB_ROOT;
+       INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
+       mdsc->last_renew_caps = jiffies;
+       INIT_LIST_HEAD(&mdsc->cap_delay_list);
+       spin_lock_init(&mdsc->cap_delay_lock);
+       INIT_LIST_HEAD(&mdsc->snap_flush_list);
+       spin_lock_init(&mdsc->snap_flush_lock);
+       mdsc->cap_flush_seq = 0;
+       INIT_LIST_HEAD(&mdsc->cap_dirty);
+       mdsc->num_cap_flushing = 0;
+       spin_lock_init(&mdsc->cap_dirty_lock);
+       init_waitqueue_head(&mdsc->cap_flushing_wq);
+       spin_lock_init(&mdsc->dentry_lru_lock);
+       INIT_LIST_HEAD(&mdsc->dentry_lru);
+       return 0;
+}
+
+/*
+ * Wait for safe replies on open mds requests.  If we time out, drop
+ * all requests from the tree to avoid dangling dentry refs.
+ */
+static void wait_requests(struct ceph_mds_client *mdsc)
+{
+       struct ceph_mds_request *req;
+       struct ceph_client *client = mdsc->client;
+
+       mutex_lock(&mdsc->mutex);
+       if (__get_oldest_req(mdsc)) {
+               mutex_unlock(&mdsc->mutex);
+
+               dout("wait_requests waiting for requests\n");
+               wait_for_completion_timeout(&mdsc->safe_umount_waiters,
+                                   client->mount_args->mount_timeout * HZ);
+
+               /* tear down remaining requests */
+               mutex_lock(&mdsc->mutex);
+               while ((req = __get_oldest_req(mdsc))) {
+                       dout("wait_requests timed out on tid %llu\n",
+                            req->r_tid);
+                       __unregister_request(mdsc, req);
+               }
+       }
+       mutex_unlock(&mdsc->mutex);
+       dout("wait_requests done\n");
+}
+
+/*
+ * called before mount is ro, and before dentries are torn down.
+ * (hmm, does this still race with new lookups?)
+ */
+void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc)
+{
+       dout("pre_umount\n");
+       mdsc->stopping = 1;
+
+       drop_leases(mdsc);
+       ceph_flush_dirty_caps(mdsc);
+       wait_requests(mdsc);
+}
+
+/*
+ * wait for all write mds requests to flush.
+ */
+static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid)
+{
+       struct ceph_mds_request *req = NULL;
+       struct rb_node *n;
+
+       mutex_lock(&mdsc->mutex);
+       dout("wait_unsafe_requests want %lld\n", want_tid);
+       req = __get_oldest_req(mdsc);
+       while (req && req->r_tid <= want_tid) {
+               if ((req->r_op & CEPH_MDS_OP_WRITE)) {
+                       /* write op */
+                       ceph_mdsc_get_request(req);
+                       mutex_unlock(&mdsc->mutex);
+                       dout("wait_unsafe_requests  wait on %llu (want %llu)\n",
+                            req->r_tid, want_tid);
+                       wait_for_completion(&req->r_safe_completion);
+                       mutex_lock(&mdsc->mutex);
+                       n = rb_next(&req->r_node);
+                       ceph_mdsc_put_request(req);
+               } else {
+                       n = rb_next(&req->r_node);
+               }
+               if (!n)
+                       break;
+               req = rb_entry(n, struct ceph_mds_request, r_node);
+       }
+       mutex_unlock(&mdsc->mutex);
+       dout("wait_unsafe_requests done\n");
+}
+
+void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
+{
+       u64 want_tid, want_flush;
+
+       dout("sync\n");
+       mutex_lock(&mdsc->mutex);
+       want_tid = mdsc->last_tid;
+       want_flush = mdsc->cap_flush_seq;
+       mutex_unlock(&mdsc->mutex);
+       dout("sync want tid %lld flush_seq %lld\n", want_tid, want_flush);
+
+       ceph_flush_dirty_caps(mdsc);
+
+       wait_unsafe_requests(mdsc, want_tid);
+       wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush));
+}
+
+
+/*
+ * called after sb is ro.
+ */
+void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
+{
+       struct ceph_mds_session *session;
+       int i;
+       int n;
+       struct ceph_client *client = mdsc->client;
+       unsigned long started, timeout = client->mount_args->mount_timeout * HZ;
+
+       dout("close_sessions\n");
+
+       mutex_lock(&mdsc->mutex);
+
+       /* close sessions */
+       started = jiffies;
+       while (time_before(jiffies, started + timeout)) {
+               dout("closing sessions\n");
+               n = 0;
+               for (i = 0; i < mdsc->max_sessions; i++) {
+                       session = __ceph_lookup_mds_session(mdsc, i);
+                       if (!session)
+                               continue;
+                       mutex_unlock(&mdsc->mutex);
+                       mutex_lock(&session->s_mutex);
+                       __close_session(mdsc, session);
+                       mutex_unlock(&session->s_mutex);
+                       ceph_put_mds_session(session);
+                       mutex_lock(&mdsc->mutex);
+                       n++;
+               }
+               if (n == 0)
+                       break;
+
+               if (client->mount_state == CEPH_MOUNT_SHUTDOWN)
+                       break;
+
+               dout("waiting for sessions to close\n");
+               mutex_unlock(&mdsc->mutex);
+               wait_for_completion_timeout(&mdsc->session_close_waiters,
+                                           timeout);
+               mutex_lock(&mdsc->mutex);
+       }
+
+       /* tear down remaining sessions */
+       for (i = 0; i < mdsc->max_sessions; i++) {
+               if (mdsc->sessions[i]) {
+                       session = get_session(mdsc->sessions[i]);
+                       __unregister_session(mdsc, session);
+                       mutex_unlock(&mdsc->mutex);
+                       mutex_lock(&session->s_mutex);
+                       remove_session_caps(session);
+                       mutex_unlock(&session->s_mutex);
+                       ceph_put_mds_session(session);
+                       mutex_lock(&mdsc->mutex);
+               }
+       }
+
+       WARN_ON(!list_empty(&mdsc->cap_delay_list));
+
+       mutex_unlock(&mdsc->mutex);
+
+       ceph_cleanup_empty_realms(mdsc);
+
+       cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+
+       dout("stopped\n");
+}
+
+void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
+{
+       dout("stop\n");
+       cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+       if (mdsc->mdsmap)
+               ceph_mdsmap_destroy(mdsc->mdsmap);
+       kfree(mdsc->sessions);
+}
+
+
+/*
+ * handle mds map update.
+ */
+void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+{
+       u32 epoch;
+       u32 maplen;
+       void *p = msg->front.iov_base;
+       void *end = p + msg->front.iov_len;
+       struct ceph_mdsmap *newmap, *oldmap;
+       struct ceph_fsid fsid;
+       int err = -EINVAL;
+
+       ceph_decode_need(&p, end, sizeof(fsid)+2*sizeof(u32), bad);
+       ceph_decode_copy(&p, &fsid, sizeof(fsid));
+       if (ceph_check_fsid(mdsc->client, &fsid) < 0)
+               return;
+       epoch = ceph_decode_32(&p);
+       maplen = ceph_decode_32(&p);
+       dout("handle_map epoch %u len %d\n", epoch, (int)maplen);
+
+       /* do we need it? */
+       ceph_monc_got_mdsmap(&mdsc->client->monc, epoch);
+       mutex_lock(&mdsc->mutex);
+       if (mdsc->mdsmap && epoch <= mdsc->mdsmap->m_epoch) {
+               dout("handle_map epoch %u <= our %u\n",
+                    epoch, mdsc->mdsmap->m_epoch);
+               mutex_unlock(&mdsc->mutex);
+               return;
+       }
+
+       newmap = ceph_mdsmap_decode(&p, end);
+       if (IS_ERR(newmap)) {
+               err = PTR_ERR(newmap);
+               goto bad_unlock;
+       }
+
+       /* swap into place */
+       if (mdsc->mdsmap) {
+               oldmap = mdsc->mdsmap;
+               mdsc->mdsmap = newmap;
+               check_new_map(mdsc, newmap, oldmap);
+               ceph_mdsmap_destroy(oldmap);
+       } else {
+               mdsc->mdsmap = newmap;  /* first mds map */
+       }
+       mdsc->client->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
+
+       __wake_requests(mdsc, &mdsc->waiting_for_map);
+
+       mutex_unlock(&mdsc->mutex);
+       schedule_delayed(mdsc);
+       return;
+
+bad_unlock:
+       mutex_unlock(&mdsc->mutex);
+bad:
+       pr_err("error decoding mdsmap %d\n", err);
+       return;
+}
+
+static struct ceph_connection *con_get(struct ceph_connection *con)
+{
+       struct ceph_mds_session *s = con->private;
+
+       if (get_session(s)) {
+               dout("mdsc con_get %p ok (%d)\n", s, atomic_read(&s->s_ref));
+               return con;
+       }
+       dout("mdsc con_get %p FAIL\n", s);
+       return NULL;
+}
+
+static void con_put(struct ceph_connection *con)
+{
+       struct ceph_mds_session *s = con->private;
+
+       ceph_put_mds_session(s);
+       dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref));
+}
+
+/*
+ * if the client is unresponsive for long enough, the mds will kill
+ * the session entirely.
+ */
+static void peer_reset(struct ceph_connection *con)
+{
+       struct ceph_mds_session *s = con->private;
+
+       pr_err("mds%d gave us the boot.  IMPLEMENT RECONNECT.\n",
+              s->s_mds);
+}
+
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_mds_client *mdsc = s->s_mdsc;
+       int type = le16_to_cpu(msg->hdr.type);
+
+       mutex_lock(&mdsc->mutex);
+       if (__verify_registered_session(mdsc, s) < 0) {
+               mutex_unlock(&mdsc->mutex);
+               goto out;
+       }
+       mutex_unlock(&mdsc->mutex);
+
+       switch (type) {
+       case CEPH_MSG_MDS_MAP:
+               ceph_mdsc_handle_map(mdsc, msg);
+               break;
+       case CEPH_MSG_CLIENT_SESSION:
+               handle_session(s, msg);
+               break;
+       case CEPH_MSG_CLIENT_REPLY:
+               handle_reply(s, msg);
+               break;
+       case CEPH_MSG_CLIENT_REQUEST_FORWARD:
+               handle_forward(mdsc, s, msg);
+               break;
+       case CEPH_MSG_CLIENT_CAPS:
+               ceph_handle_caps(s, msg);
+               break;
+       case CEPH_MSG_CLIENT_SNAP:
+               ceph_handle_snap(mdsc, s, msg);
+               break;
+       case CEPH_MSG_CLIENT_LEASE:
+               handle_lease(mdsc, s, msg);
+               break;
+
+       default:
+               pr_err("received unknown message type %d %s\n", type,
+                      ceph_msg_type_name(type));
+       }
+out:
+       ceph_msg_put(msg);
+}
+
+/*
+ * authentication
+ */
+static int get_authorizer(struct ceph_connection *con,
+                         void **buf, int *len, int *proto,
+                         void **reply_buf, int *reply_len, int force_new)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_mds_client *mdsc = s->s_mdsc;
+       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+       int ret = 0;
+
+       if (force_new && s->s_authorizer) {
+               ac->ops->destroy_authorizer(ac, s->s_authorizer);
+               s->s_authorizer = NULL;
+       }
+       if (s->s_authorizer == NULL) {
+               if (ac->ops->create_authorizer) {
+                       ret = ac->ops->create_authorizer(
+                               ac, CEPH_ENTITY_TYPE_MDS,
+                               &s->s_authorizer,
+                               &s->s_authorizer_buf,
+                               &s->s_authorizer_buf_len,
+                               &s->s_authorizer_reply_buf,
+                               &s->s_authorizer_reply_buf_len);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       *proto = ac->protocol;
+       *buf = s->s_authorizer_buf;
+       *len = s->s_authorizer_buf_len;
+       *reply_buf = s->s_authorizer_reply_buf;
+       *reply_len = s->s_authorizer_reply_buf_len;
+       return 0;
+}
+
+
+static int verify_authorizer_reply(struct ceph_connection *con, int len)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_mds_client *mdsc = s->s_mdsc;
+       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+
+       return ac->ops->verify_authorizer_reply(ac, s->s_authorizer, len);
+}
+
+static int invalidate_authorizer(struct ceph_connection *con)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_mds_client *mdsc = s->s_mdsc;
+       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+
+       if (ac->ops->invalidate_authorizer)
+               ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_MDS);
+
+       return ceph_monc_validate_auth(&mdsc->client->monc);
+}
+
+const static struct ceph_connection_operations mds_con_ops = {
+       .get = con_get,
+       .put = con_put,
+       .dispatch = dispatch,
+       .get_authorizer = get_authorizer,
+       .verify_authorizer_reply = verify_authorizer_reply,
+       .invalidate_authorizer = invalidate_authorizer,
+       .peer_reset = peer_reset,
+};
+
+
+
+
+/* eof */
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
new file mode 100644 (file)
index 0000000..961cc6f
--- /dev/null
@@ -0,0 +1,335 @@
+#ifndef _FS_CEPH_MDS_CLIENT_H
+#define _FS_CEPH_MDS_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+
+#include "types.h"
+#include "messenger.h"
+#include "mdsmap.h"
+
+/*
+ * Some lock dependencies:
+ *
+ * session->s_mutex
+ *         mdsc->mutex
+ *
+ *         mdsc->snap_rwsem
+ *
+ *         inode->i_lock
+ *                 mdsc->snap_flush_lock
+ *                 mdsc->cap_delay_lock
+ *
+ */
+
+struct ceph_client;
+struct ceph_cap;
+
+/*
+ * parsed info about a single inode.  pointers are into the encoded
+ * on-wire structures within the mds reply message payload.
+ */
+struct ceph_mds_reply_info_in {
+       struct ceph_mds_reply_inode *in;
+       u32 symlink_len;
+       char *symlink;
+       u32 xattr_len;
+       char *xattr_data;
+};
+
+/*
+ * parsed info about an mds reply, including information about the
+ * target inode and/or its parent directory and dentry, and directory
+ * contents (for readdir results).
+ */
+struct ceph_mds_reply_info_parsed {
+       struct ceph_mds_reply_head    *head;
+
+       struct ceph_mds_reply_info_in diri, targeti;
+       struct ceph_mds_reply_dirfrag *dirfrag;
+       char                          *dname;
+       u32                           dname_len;
+       struct ceph_mds_reply_lease   *dlease;
+
+       struct ceph_mds_reply_dirfrag *dir_dir;
+       int                           dir_nr;
+       char                          **dir_dname;
+       u32                           *dir_dname_len;
+       struct ceph_mds_reply_lease   **dir_dlease;
+       struct ceph_mds_reply_info_in *dir_in;
+       u8                            dir_complete, dir_end;
+
+       /* encoded blob describing snapshot contexts for certain
+          operations (e.g., open) */
+       void *snapblob;
+       int snapblob_len;
+};
+
+
+/*
+ * cap releases are batched and sent to the MDS en masse.
+ */
+#define CEPH_CAPS_PER_RELEASE ((PAGE_CACHE_SIZE -                      \
+                               sizeof(struct ceph_mds_cap_release)) /  \
+                              sizeof(struct ceph_mds_cap_item))
+
+
+/*
+ * state associated with each MDS<->client session
+ */
+enum {
+       CEPH_MDS_SESSION_NEW = 1,
+       CEPH_MDS_SESSION_OPENING = 2,
+       CEPH_MDS_SESSION_OPEN = 3,
+       CEPH_MDS_SESSION_HUNG = 4,
+       CEPH_MDS_SESSION_CLOSING = 5,
+       CEPH_MDS_SESSION_RESTARTING = 6,
+       CEPH_MDS_SESSION_RECONNECTING = 7,
+};
+
+struct ceph_mds_session {
+       struct ceph_mds_client *s_mdsc;
+       int               s_mds;
+       int               s_state;
+       unsigned long     s_ttl;      /* time until mds kills us */
+       u64               s_seq;      /* incoming msg seq # */
+       struct mutex      s_mutex;    /* serialize session messages */
+
+       struct ceph_connection s_con;
+
+       struct ceph_authorizer *s_authorizer;
+       void             *s_authorizer_buf, *s_authorizer_reply_buf;
+       size_t            s_authorizer_buf_len, s_authorizer_reply_buf_len;
+
+       /* protected by s_cap_lock */
+       spinlock_t        s_cap_lock;
+       u32               s_cap_gen;  /* inc each time we get mds stale msg */
+       unsigned long     s_cap_ttl;  /* when session caps expire */
+       struct list_head  s_caps;     /* all caps issued by this session */
+       int               s_nr_caps, s_trim_caps;
+       int               s_num_cap_releases;
+       struct list_head  s_cap_releases; /* waiting cap_release messages */
+       struct list_head  s_cap_releases_done; /* ready to send */
+       struct ceph_cap  *s_cap_iterator;
+
+       /* protected by mutex */
+       struct list_head  s_cap_flushing;     /* inodes w/ flushing caps */
+       struct list_head  s_cap_snaps_flushing;
+       unsigned long     s_renew_requested; /* last time we sent a renew req */
+       u64               s_renew_seq;
+
+       atomic_t          s_ref;
+       struct list_head  s_waiting;  /* waiting requests */
+       struct list_head  s_unsafe;   /* unsafe requests */
+};
+
+/*
+ * modes of choosing which MDS to send a request to
+ */
+enum {
+       USE_ANY_MDS,
+       USE_RANDOM_MDS,
+       USE_AUTH_MDS,   /* prefer authoritative mds for this metadata item */
+};
+
+struct ceph_mds_request;
+struct ceph_mds_client;
+
+/*
+ * request completion callback
+ */
+typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc,
+                                            struct ceph_mds_request *req);
+
+/*
+ * an in-flight mds request
+ */
+struct ceph_mds_request {
+       u64 r_tid;                   /* transaction id */
+       struct rb_node r_node;
+
+       int r_op;                    /* mds op code */
+       int r_mds;
+
+       /* operation on what? */
+       struct inode *r_inode;              /* arg1 */
+       struct dentry *r_dentry;            /* arg1 */
+       struct dentry *r_old_dentry;        /* arg2: rename from or link from */
+       char *r_path1, *r_path2;
+       struct ceph_vino r_ino1, r_ino2;
+
+       struct inode *r_locked_dir; /* dir (if any) i_mutex locked by vfs */
+       struct inode *r_target_inode;       /* resulting inode */
+
+       union ceph_mds_request_args r_args;
+       int r_fmode;        /* file mode, if expecting cap */
+
+       /* for choosing which mds to send this request to */
+       int r_direct_mode;
+       u32 r_direct_hash;      /* choose dir frag based on this dentry hash */
+       bool r_direct_is_hash;  /* true if r_direct_hash is valid */
+
+       /* data payload is used for xattr ops */
+       struct page **r_pages;
+       int r_num_pages;
+       int r_data_len;
+
+       /* what caps shall we drop? */
+       int r_inode_drop, r_inode_unless;
+       int r_dentry_drop, r_dentry_unless;
+       int r_old_dentry_drop, r_old_dentry_unless;
+       struct inode *r_old_inode;
+       int r_old_inode_drop, r_old_inode_unless;
+
+       struct ceph_msg  *r_request;  /* original request */
+       struct ceph_msg  *r_reply;
+       struct ceph_mds_reply_info_parsed r_reply_info;
+       int r_err;
+       bool r_aborted;
+
+       unsigned long r_timeout;  /* optional.  jiffies */
+       unsigned long r_started;  /* start time to measure timeout against */
+       unsigned long r_request_started; /* start time for mds request only,
+                                           used to measure lease durations */
+
+       /* link unsafe requests to parent directory, for fsync */
+       struct inode    *r_unsafe_dir;
+       struct list_head r_unsafe_dir_item;
+
+       struct ceph_mds_session *r_session;
+
+       int               r_attempts;   /* resend attempts */
+       int               r_num_fwd;    /* number of forward attempts */
+       int               r_num_stale;
+       int               r_resend_mds; /* mds to resend to next, if any*/
+
+       struct kref       r_kref;
+       struct list_head  r_wait;
+       struct completion r_completion;
+       struct completion r_safe_completion;
+       ceph_mds_request_callback_t r_callback;
+       struct list_head  r_unsafe_item;  /* per-session unsafe list item */
+       bool              r_got_unsafe, r_got_safe;
+
+       bool              r_did_prepopulate;
+       u32               r_readdir_offset;
+
+       struct ceph_cap_reservation r_caps_reservation;
+       int r_num_caps;
+};
+
+/*
+ * mds client state
+ */
+struct ceph_mds_client {
+       struct ceph_client      *client;
+       struct mutex            mutex;         /* all nested structures */
+
+       struct ceph_mdsmap      *mdsmap;
+       struct completion       safe_umount_waiters, session_close_waiters;
+       struct list_head        waiting_for_map;
+
+       struct ceph_mds_session **sessions;    /* NULL for mds if no session */
+       int                     max_sessions;  /* len of s_mds_sessions */
+       int                     stopping;      /* true if shutting down */
+
+       /*
+        * snap_rwsem will cover cap linkage into snaprealms, and
+        * realm snap contexts.  (later, we can do per-realm snap
+        * contexts locks..)  the empty list contains realms with no
+        * references (implying they contain no inodes with caps) that
+        * should be destroyed.
+        */
+       struct rw_semaphore     snap_rwsem;
+       struct rb_root          snap_realms;
+       struct list_head        snap_empty;
+       spinlock_t              snap_empty_lock;  /* protect snap_empty */
+
+       u64                    last_tid;      /* most recent mds request */
+       struct rb_root         request_tree;  /* pending mds requests */
+       struct delayed_work    delayed_work;  /* delayed work */
+       unsigned long    last_renew_caps;  /* last time we renewed our caps */
+       struct list_head cap_delay_list;   /* caps with delayed release */
+       spinlock_t       cap_delay_lock;   /* protects cap_delay_list */
+       struct list_head snap_flush_list;  /* cap_snaps ready to flush */
+       spinlock_t       snap_flush_lock;
+
+       u64               cap_flush_seq;
+       struct list_head  cap_dirty;        /* inodes with dirty caps */
+       int               num_cap_flushing; /* # caps we are flushing */
+       spinlock_t        cap_dirty_lock;   /* protects above items */
+       wait_queue_head_t cap_flushing_wq;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry     *debugfs_file;
+#endif
+
+       spinlock_t        dentry_lru_lock;
+       struct list_head  dentry_lru;
+       int               num_dentry;
+};
+
+extern const char *ceph_mds_op_name(int op);
+
+extern struct ceph_mds_session *
+__ceph_lookup_mds_session(struct ceph_mds_client *, int mds);
+
+static inline struct ceph_mds_session *
+ceph_get_mds_session(struct ceph_mds_session *s)
+{
+       atomic_inc(&s->s_ref);
+       return s;
+}
+
+extern void ceph_put_mds_session(struct ceph_mds_session *s);
+
+extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc,
+                            struct ceph_msg *msg, int mds);
+
+extern int ceph_mdsc_init(struct ceph_mds_client *mdsc,
+                          struct ceph_client *client);
+extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc);
+extern void ceph_mdsc_stop(struct ceph_mds_client *mdsc);
+
+extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
+
+extern void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc,
+                                   struct inode *inode,
+                                   struct dentry *dn, int mask);
+
+extern struct ceph_mds_request *
+ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode);
+extern void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+                                    struct ceph_mds_request *req);
+extern int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
+                               struct inode *dir,
+                               struct ceph_mds_request *req);
+static inline void ceph_mdsc_get_request(struct ceph_mds_request *req)
+{
+       kref_get(&req->r_kref);
+}
+extern void ceph_mdsc_release_request(struct kref *kref);
+static inline void ceph_mdsc_put_request(struct ceph_mds_request *req)
+{
+       kref_put(&req->r_kref, ceph_mdsc_release_request);
+}
+
+extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
+
+extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
+                                 int stop_on_nosnap);
+
+extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry);
+extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
+                                    struct inode *inode,
+                                    struct dentry *dentry, char action,
+                                    u32 seq);
+
+extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc,
+                                struct ceph_msg *msg);
+
+#endif
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
new file mode 100644 (file)
index 0000000..c4c498e
--- /dev/null
@@ -0,0 +1,174 @@
+#include "ceph_debug.h"
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "mdsmap.h"
+#include "messenger.h"
+#include "decode.h"
+
+#include "super.h"
+
+
+/*
+ * choose a random mds that is "up" (i.e. has a state > 0), or -1.
+ */
+int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m)
+{
+       int n = 0;
+       int i;
+       char r;
+
+       /* count */
+       for (i = 0; i < m->m_max_mds; i++)
+               if (m->m_info[i].state > 0)
+                       n++;
+       if (n == 0)
+               return -1;
+
+       /* pick */
+       get_random_bytes(&r, 1);
+       n = r % n;
+       i = 0;
+       for (i = 0; n > 0; i++, n--)
+               while (m->m_info[i].state <= 0)
+                       i++;
+
+       return i;
+}
+
+/*
+ * Decode an MDS map
+ *
+ * Ignore any fields we don't care about (there are quite a few of
+ * them).
+ */
+struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
+{
+       struct ceph_mdsmap *m;
+       const void *start = *p;
+       int i, j, n;
+       int err = -EINVAL;
+       u16 version;
+
+       m = kzalloc(sizeof(*m), GFP_NOFS);
+       if (m == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       ceph_decode_16_safe(p, end, version, bad);
+
+       ceph_decode_need(p, end, 8*sizeof(u32) + sizeof(u64), bad);
+       m->m_epoch = ceph_decode_32(p);
+       m->m_client_epoch = ceph_decode_32(p);
+       m->m_last_failure = ceph_decode_32(p);
+       m->m_root = ceph_decode_32(p);
+       m->m_session_timeout = ceph_decode_32(p);
+       m->m_session_autoclose = ceph_decode_32(p);
+       m->m_max_file_size = ceph_decode_64(p);
+       m->m_max_mds = ceph_decode_32(p);
+
+       m->m_info = kcalloc(m->m_max_mds, sizeof(*m->m_info), GFP_NOFS);
+       if (m->m_info == NULL)
+               goto badmem;
+
+       /* pick out active nodes from mds_info (state > 0) */
+       n = ceph_decode_32(p);
+       for (i = 0; i < n; i++) {
+               u64 global_id;
+               u32 namelen;
+               s32 mds, inc, state;
+               u64 state_seq;
+               u8 infoversion;
+               struct ceph_entity_addr addr;
+               u32 num_export_targets;
+               void *pexport_targets = NULL;
+
+               ceph_decode_need(p, end, sizeof(u64)*2 + 1 + sizeof(u32), bad);
+               global_id = ceph_decode_64(p);
+               infoversion = ceph_decode_8(p);
+               *p += sizeof(u64);
+               namelen = ceph_decode_32(p);  /* skip mds name */
+               *p += namelen;
+
+               ceph_decode_need(p, end,
+                                4*sizeof(u32) + sizeof(u64) +
+                                sizeof(addr) + sizeof(struct ceph_timespec),
+                                bad);
+               mds = ceph_decode_32(p);
+               inc = ceph_decode_32(p);
+               state = ceph_decode_32(p);
+               state_seq = ceph_decode_64(p);
+               ceph_decode_copy(p, &addr, sizeof(addr));
+               ceph_decode_addr(&addr);
+               *p += sizeof(struct ceph_timespec);
+               *p += sizeof(u32);
+               ceph_decode_32_safe(p, end, namelen, bad);
+               *p += namelen;
+               if (infoversion >= 2) {
+                       ceph_decode_32_safe(p, end, num_export_targets, bad);
+                       pexport_targets = *p;
+                       *p += num_export_targets * sizeof(u32);
+               } else {
+                       num_export_targets = 0;
+               }
+
+               dout("mdsmap_decode %d/%d %lld mds%d.%d %s %s\n",
+                    i+1, n, global_id, mds, inc, pr_addr(&addr.in_addr),
+                    ceph_mds_state_name(state));
+               if (mds >= 0 && mds < m->m_max_mds && state > 0) {
+                       m->m_info[mds].global_id = global_id;
+                       m->m_info[mds].state = state;
+                       m->m_info[mds].addr = addr;
+                       m->m_info[mds].num_export_targets = num_export_targets;
+                       if (num_export_targets) {
+                               m->m_info[mds].export_targets =
+                                       kcalloc(num_export_targets, sizeof(u32),
+                                               GFP_NOFS);
+                               for (j = 0; j < num_export_targets; j++)
+                                       m->m_info[mds].export_targets[j] =
+                                              ceph_decode_32(&pexport_targets);
+                       } else {
+                               m->m_info[mds].export_targets = NULL;
+                       }
+               }
+       }
+
+       /* pg_pools */
+       ceph_decode_32_safe(p, end, n, bad);
+       m->m_num_data_pg_pools = n;
+       m->m_data_pg_pools = kcalloc(n, sizeof(u32), GFP_NOFS);
+       if (!m->m_data_pg_pools)
+               goto badmem;
+       ceph_decode_need(p, end, sizeof(u32)*(n+1), bad);
+       for (i = 0; i < n; i++)
+               m->m_data_pg_pools[i] = ceph_decode_32(p);
+       m->m_cas_pg_pool = ceph_decode_32(p);
+
+       /* ok, we don't care about the rest. */
+       dout("mdsmap_decode success epoch %u\n", m->m_epoch);
+       return m;
+
+badmem:
+       err = -ENOMEM;
+bad:
+       pr_err("corrupt mdsmap\n");
+       print_hex_dump(KERN_DEBUG, "mdsmap: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      start, end - start, true);
+       ceph_mdsmap_destroy(m);
+       return ERR_PTR(-EINVAL);
+}
+
+void ceph_mdsmap_destroy(struct ceph_mdsmap *m)
+{
+       int i;
+
+       for (i = 0; i < m->m_max_mds; i++)
+               kfree(m->m_info[i].export_targets);
+       kfree(m->m_info);
+       kfree(m->m_data_pg_pools);
+       kfree(m);
+}
diff --git a/fs/ceph/mdsmap.h b/fs/ceph/mdsmap.h
new file mode 100644 (file)
index 0000000..eacc131
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _FS_CEPH_MDSMAP_H
+#define _FS_CEPH_MDSMAP_H
+
+#include "types.h"
+
+/*
+ * mds map - describe servers in the mds cluster.
+ *
+ * we limit fields to those the client actually xcares about
+ */
+struct ceph_mds_info {
+       u64 global_id;
+       struct ceph_entity_addr addr;
+       s32 state;
+       int num_export_targets;
+       u32 *export_targets;
+};
+
+struct ceph_mdsmap {
+       u32 m_epoch, m_client_epoch, m_last_failure;
+       u32 m_root;
+       u32 m_session_timeout;          /* seconds */
+       u32 m_session_autoclose;        /* seconds */
+       u64 m_max_file_size;
+       u32 m_max_mds;                  /* size of m_addr, m_state arrays */
+       struct ceph_mds_info *m_info;
+
+       /* which object pools file data can be stored in */
+       int m_num_data_pg_pools;
+       u32 *m_data_pg_pools;
+       u32 m_cas_pg_pool;
+};
+
+static inline struct ceph_entity_addr *
+ceph_mdsmap_get_addr(struct ceph_mdsmap *m, int w)
+{
+       if (w >= m->m_max_mds)
+               return NULL;
+       return &m->m_info[w].addr;
+}
+
+static inline int ceph_mdsmap_get_state(struct ceph_mdsmap *m, int w)
+{
+       BUG_ON(w < 0);
+       if (w >= m->m_max_mds)
+               return CEPH_MDS_STATE_DNE;
+       return m->m_info[w].state;
+}
+
+extern int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m);
+extern struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end);
+extern void ceph_mdsmap_destroy(struct ceph_mdsmap *m);
+
+#endif
diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c
new file mode 100644 (file)
index 0000000..781656a
--- /dev/null
@@ -0,0 +1,2240 @@
+#include "ceph_debug.h"
+
+#include <linux/crc32c.h>
+#include <linux/ctype.h>
+#include <linux/highmem.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <net/tcp.h>
+
+#include "super.h"
+#include "messenger.h"
+#include "decode.h"
+#include "pagelist.h"
+
+/*
+ * Ceph uses the messenger to exchange ceph_msg messages with other
+ * hosts in the system.  The messenger provides ordered and reliable
+ * delivery.  We tolerate TCP disconnects by reconnecting (with
+ * exponential backoff) in the case of a fault (disconnection, bad
+ * crc, protocol error).  Acks allow sent messages to be discarded by
+ * the sender.
+ */
+
+/* static tag bytes (protocol control messages) */
+static char tag_msg = CEPH_MSGR_TAG_MSG;
+static char tag_ack = CEPH_MSGR_TAG_ACK;
+static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE;
+
+
+static void queue_con(struct ceph_connection *con);
+static void con_work(struct work_struct *);
+static void ceph_fault(struct ceph_connection *con);
+
+const char *ceph_name_type_str(int t)
+{
+       switch (t) {
+       case CEPH_ENTITY_TYPE_MON: return "mon";
+       case CEPH_ENTITY_TYPE_MDS: return "mds";
+       case CEPH_ENTITY_TYPE_OSD: return "osd";
+       case CEPH_ENTITY_TYPE_CLIENT: return "client";
+       case CEPH_ENTITY_TYPE_ADMIN: return "admin";
+       default: return "???";
+       }
+}
+
+/*
+ * nicely render a sockaddr as a string.
+ */
+#define MAX_ADDR_STR 20
+static char addr_str[MAX_ADDR_STR][40];
+static DEFINE_SPINLOCK(addr_str_lock);
+static int last_addr_str;
+
+const char *pr_addr(const struct sockaddr_storage *ss)
+{
+       int i;
+       char *s;
+       struct sockaddr_in *in4 = (void *)ss;
+       unsigned char *quad = (void *)&in4->sin_addr.s_addr;
+       struct sockaddr_in6 *in6 = (void *)ss;
+
+       spin_lock(&addr_str_lock);
+       i = last_addr_str++;
+       if (last_addr_str == MAX_ADDR_STR)
+               last_addr_str = 0;
+       spin_unlock(&addr_str_lock);
+       s = addr_str[i];
+
+       switch (ss->ss_family) {
+       case AF_INET:
+               sprintf(s, "%u.%u.%u.%u:%u",
+                       (unsigned int)quad[0],
+                       (unsigned int)quad[1],
+                       (unsigned int)quad[2],
+                       (unsigned int)quad[3],
+                       (unsigned int)ntohs(in4->sin_port));
+               break;
+
+       case AF_INET6:
+               sprintf(s, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%u",
+                       in6->sin6_addr.s6_addr16[0],
+                       in6->sin6_addr.s6_addr16[1],
+                       in6->sin6_addr.s6_addr16[2],
+                       in6->sin6_addr.s6_addr16[3],
+                       in6->sin6_addr.s6_addr16[4],
+                       in6->sin6_addr.s6_addr16[5],
+                       in6->sin6_addr.s6_addr16[6],
+                       in6->sin6_addr.s6_addr16[7],
+                       (unsigned int)ntohs(in6->sin6_port));
+               break;
+
+       default:
+               sprintf(s, "(unknown sockaddr family %d)", (int)ss->ss_family);
+       }
+
+       return s;
+}
+
+static void encode_my_addr(struct ceph_messenger *msgr)
+{
+       memcpy(&msgr->my_enc_addr, &msgr->inst.addr, sizeof(msgr->my_enc_addr));
+       ceph_encode_addr(&msgr->my_enc_addr);
+}
+
+/*
+ * work queue for all reading and writing to/from the socket.
+ */
+struct workqueue_struct *ceph_msgr_wq;
+
+int __init ceph_msgr_init(void)
+{
+       ceph_msgr_wq = create_workqueue("ceph-msgr");
+       if (IS_ERR(ceph_msgr_wq)) {
+               int ret = PTR_ERR(ceph_msgr_wq);
+               pr_err("msgr_init failed to create workqueue: %d\n", ret);
+               ceph_msgr_wq = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+void ceph_msgr_exit(void)
+{
+       destroy_workqueue(ceph_msgr_wq);
+}
+
+/*
+ * socket callback functions
+ */
+
+/* data available on socket, or listen socket received a connect */
+static void ceph_data_ready(struct sock *sk, int count_unused)
+{
+       struct ceph_connection *con =
+               (struct ceph_connection *)sk->sk_user_data;
+       if (sk->sk_state != TCP_CLOSE_WAIT) {
+               dout("ceph_data_ready on %p state = %lu, queueing work\n",
+                    con, con->state);
+               queue_con(con);
+       }
+}
+
+/* socket has buffer space for writing */
+static void ceph_write_space(struct sock *sk)
+{
+       struct ceph_connection *con =
+               (struct ceph_connection *)sk->sk_user_data;
+
+       /* only queue to workqueue if there is data we want to write. */
+       if (test_bit(WRITE_PENDING, &con->state)) {
+               dout("ceph_write_space %p queueing write work\n", con);
+               queue_con(con);
+       } else {
+               dout("ceph_write_space %p nothing to write\n", con);
+       }
+
+       /* since we have our own write_space, clear the SOCK_NOSPACE flag */
+       clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+}
+
+/* socket's state has changed */
+static void ceph_state_change(struct sock *sk)
+{
+       struct ceph_connection *con =
+               (struct ceph_connection *)sk->sk_user_data;
+
+       dout("ceph_state_change %p state = %lu sk_state = %u\n",
+            con, con->state, sk->sk_state);
+
+       if (test_bit(CLOSED, &con->state))
+               return;
+
+       switch (sk->sk_state) {
+       case TCP_CLOSE:
+               dout("ceph_state_change TCP_CLOSE\n");
+       case TCP_CLOSE_WAIT:
+               dout("ceph_state_change TCP_CLOSE_WAIT\n");
+               if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) {
+                       if (test_bit(CONNECTING, &con->state))
+                               con->error_msg = "connection failed";
+                       else
+                               con->error_msg = "socket closed";
+                       queue_con(con);
+               }
+               break;
+       case TCP_ESTABLISHED:
+               dout("ceph_state_change TCP_ESTABLISHED\n");
+               queue_con(con);
+               break;
+       }
+}
+
+/*
+ * set up socket callbacks
+ */
+static void set_sock_callbacks(struct socket *sock,
+                              struct ceph_connection *con)
+{
+       struct sock *sk = sock->sk;
+       sk->sk_user_data = (void *)con;
+       sk->sk_data_ready = ceph_data_ready;
+       sk->sk_write_space = ceph_write_space;
+       sk->sk_state_change = ceph_state_change;
+}
+
+
+/*
+ * socket helpers
+ */
+
+/*
+ * initiate connection to a remote socket.
+ */
+static struct socket *ceph_tcp_connect(struct ceph_connection *con)
+{
+       struct sockaddr *paddr = (struct sockaddr *)&con->peer_addr.in_addr;
+       struct socket *sock;
+       int ret;
+
+       BUG_ON(con->sock);
+       ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+       if (ret)
+               return ERR_PTR(ret);
+       con->sock = sock;
+       sock->sk->sk_allocation = GFP_NOFS;
+
+       set_sock_callbacks(sock, con);
+
+       dout("connect %s\n", pr_addr(&con->peer_addr.in_addr));
+
+       ret = sock->ops->connect(sock, paddr, sizeof(*paddr), O_NONBLOCK);
+       if (ret == -EINPROGRESS) {
+               dout("connect %s EINPROGRESS sk_state = %u\n",
+                    pr_addr(&con->peer_addr.in_addr),
+                    sock->sk->sk_state);
+               ret = 0;
+       }
+       if (ret < 0) {
+               pr_err("connect %s error %d\n",
+                      pr_addr(&con->peer_addr.in_addr), ret);
+               sock_release(sock);
+               con->sock = NULL;
+               con->error_msg = "connect error";
+       }
+
+       if (ret < 0)
+               return ERR_PTR(ret);
+       return sock;
+}
+
+static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
+{
+       struct kvec iov = {buf, len};
+       struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+
+       return kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+}
+
+/*
+ * write something.  @more is true if caller will be sending more data
+ * shortly.
+ */
+static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
+                    size_t kvlen, size_t len, int more)
+{
+       struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+
+       if (more)
+               msg.msg_flags |= MSG_MORE;
+       else
+               msg.msg_flags |= MSG_EOR;  /* superfluous, but what the hell */
+
+       return kernel_sendmsg(sock, &msg, iov, kvlen, len);
+}
+
+
+/*
+ * Shutdown/close the socket for the given connection.
+ */
+static int con_close_socket(struct ceph_connection *con)
+{
+       int rc;
+
+       dout("con_close_socket on %p sock %p\n", con, con->sock);
+       if (!con->sock)
+               return 0;
+       set_bit(SOCK_CLOSED, &con->state);
+       rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR);
+       sock_release(con->sock);
+       con->sock = NULL;
+       clear_bit(SOCK_CLOSED, &con->state);
+       return rc;
+}
+
+/*
+ * Reset a connection.  Discard all incoming and outgoing messages
+ * and clear *_seq state.
+ */
+static void ceph_msg_remove(struct ceph_msg *msg)
+{
+       list_del_init(&msg->list_head);
+       ceph_msg_put(msg);
+}
+static void ceph_msg_remove_list(struct list_head *head)
+{
+       while (!list_empty(head)) {
+               struct ceph_msg *msg = list_first_entry(head, struct ceph_msg,
+                                                       list_head);
+               ceph_msg_remove(msg);
+       }
+}
+
+static void reset_connection(struct ceph_connection *con)
+{
+       /* reset connection, out_queue, msg_ and connect_seq */
+       /* discard existing out_queue and msg_seq */
+       ceph_msg_remove_list(&con->out_queue);
+       ceph_msg_remove_list(&con->out_sent);
+
+       if (con->in_msg) {
+               ceph_msg_put(con->in_msg);
+               con->in_msg = NULL;
+       }
+
+       con->connect_seq = 0;
+       con->out_seq = 0;
+       if (con->out_msg) {
+               ceph_msg_put(con->out_msg);
+               con->out_msg = NULL;
+       }
+       con->in_seq = 0;
+}
+
+/*
+ * mark a peer down.  drop any open connections.
+ */
+void ceph_con_close(struct ceph_connection *con)
+{
+       dout("con_close %p peer %s\n", con, pr_addr(&con->peer_addr.in_addr));
+       set_bit(CLOSED, &con->state);  /* in case there's queued work */
+       clear_bit(STANDBY, &con->state);  /* avoid connect_seq bump */
+       clear_bit(LOSSYTX, &con->state);  /* so we retry next connect */
+       clear_bit(KEEPALIVE_PENDING, &con->state);
+       clear_bit(WRITE_PENDING, &con->state);
+       mutex_lock(&con->mutex);
+       reset_connection(con);
+       cancel_delayed_work(&con->work);
+       mutex_unlock(&con->mutex);
+       queue_con(con);
+}
+
+/*
+ * Reopen a closed connection, with a new peer address.
+ */
+void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr)
+{
+       dout("con_open %p %s\n", con, pr_addr(&addr->in_addr));
+       set_bit(OPENING, &con->state);
+       clear_bit(CLOSED, &con->state);
+       memcpy(&con->peer_addr, addr, sizeof(*addr));
+       con->delay = 0;      /* reset backoff memory */
+       queue_con(con);
+}
+
+/*
+ * generic get/put
+ */
+struct ceph_connection *ceph_con_get(struct ceph_connection *con)
+{
+       dout("con_get %p nref = %d -> %d\n", con,
+            atomic_read(&con->nref), atomic_read(&con->nref) + 1);
+       if (atomic_inc_not_zero(&con->nref))
+               return con;
+       return NULL;
+}
+
+void ceph_con_put(struct ceph_connection *con)
+{
+       dout("con_put %p nref = %d -> %d\n", con,
+            atomic_read(&con->nref), atomic_read(&con->nref) - 1);
+       BUG_ON(atomic_read(&con->nref) == 0);
+       if (atomic_dec_and_test(&con->nref)) {
+               BUG_ON(con->sock);
+               kfree(con);
+       }
+}
+
+/*
+ * initialize a new connection.
+ */
+void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con)
+{
+       dout("con_init %p\n", con);
+       memset(con, 0, sizeof(*con));
+       atomic_set(&con->nref, 1);
+       con->msgr = msgr;
+       mutex_init(&con->mutex);
+       INIT_LIST_HEAD(&con->out_queue);
+       INIT_LIST_HEAD(&con->out_sent);
+       INIT_DELAYED_WORK(&con->work, con_work);
+}
+
+
+/*
+ * We maintain a global counter to order connection attempts.  Get
+ * a unique seq greater than @gt.
+ */
+static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt)
+{
+       u32 ret;
+
+       spin_lock(&msgr->global_seq_lock);
+       if (msgr->global_seq < gt)
+               msgr->global_seq = gt;
+       ret = ++msgr->global_seq;
+       spin_unlock(&msgr->global_seq_lock);
+       return ret;
+}
+
+
+/*
+ * Prepare footer for currently outgoing message, and finish things
+ * off.  Assumes out_kvec* are already valid.. we just add on to the end.
+ */
+static void prepare_write_message_footer(struct ceph_connection *con, int v)
+{
+       struct ceph_msg *m = con->out_msg;
+
+       dout("prepare_write_message_footer %p\n", con);
+       con->out_kvec_is_msg = true;
+       con->out_kvec[v].iov_base = &m->footer;
+       con->out_kvec[v].iov_len = sizeof(m->footer);
+       con->out_kvec_bytes += sizeof(m->footer);
+       con->out_kvec_left++;
+       con->out_more = m->more_to_follow;
+       con->out_msg_done = true;
+}
+
+/*
+ * Prepare headers for the next outgoing message.
+ */
+static void prepare_write_message(struct ceph_connection *con)
+{
+       struct ceph_msg *m;
+       int v = 0;
+
+       con->out_kvec_bytes = 0;
+       con->out_kvec_is_msg = true;
+       con->out_msg_done = false;
+
+       /* Sneak an ack in there first?  If we can get it into the same
+        * TCP packet that's a good thing. */
+       if (con->in_seq > con->in_seq_acked) {
+               con->in_seq_acked = con->in_seq;
+               con->out_kvec[v].iov_base = &tag_ack;
+               con->out_kvec[v++].iov_len = 1;
+               con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
+               con->out_kvec[v].iov_base = &con->out_temp_ack;
+               con->out_kvec[v++].iov_len = sizeof(con->out_temp_ack);
+               con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+       }
+
+       m = list_first_entry(&con->out_queue,
+                      struct ceph_msg, list_head);
+       con->out_msg = m;
+       if (test_bit(LOSSYTX, &con->state)) {
+               list_del_init(&m->list_head);
+       } else {
+               /* put message on sent list */
+               ceph_msg_get(m);
+               list_move_tail(&m->list_head, &con->out_sent);
+       }
+
+       m->hdr.seq = cpu_to_le64(++con->out_seq);
+
+       dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n",
+            m, con->out_seq, le16_to_cpu(m->hdr.type),
+            le32_to_cpu(m->hdr.front_len), le32_to_cpu(m->hdr.middle_len),
+            le32_to_cpu(m->hdr.data_len),
+            m->nr_pages);
+       BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len);
+
+       /* tag + hdr + front + middle */
+       con->out_kvec[v].iov_base = &tag_msg;
+       con->out_kvec[v++].iov_len = 1;
+       con->out_kvec[v].iov_base = &m->hdr;
+       con->out_kvec[v++].iov_len = sizeof(m->hdr);
+       con->out_kvec[v++] = m->front;
+       if (m->middle)
+               con->out_kvec[v++] = m->middle->vec;
+       con->out_kvec_left = v;
+       con->out_kvec_bytes += 1 + sizeof(m->hdr) + m->front.iov_len +
+               (m->middle ? m->middle->vec.iov_len : 0);
+       con->out_kvec_cur = con->out_kvec;
+
+       /* fill in crc (except data pages), footer */
+       con->out_msg->hdr.crc =
+               cpu_to_le32(crc32c(0, (void *)&m->hdr,
+                                     sizeof(m->hdr) - sizeof(m->hdr.crc)));
+       con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE;
+       con->out_msg->footer.front_crc =
+               cpu_to_le32(crc32c(0, m->front.iov_base, m->front.iov_len));
+       if (m->middle)
+               con->out_msg->footer.middle_crc =
+                       cpu_to_le32(crc32c(0, m->middle->vec.iov_base,
+                                          m->middle->vec.iov_len));
+       else
+               con->out_msg->footer.middle_crc = 0;
+       con->out_msg->footer.data_crc = 0;
+       dout("prepare_write_message front_crc %u data_crc %u\n",
+            le32_to_cpu(con->out_msg->footer.front_crc),
+            le32_to_cpu(con->out_msg->footer.middle_crc));
+
+       /* is there a data payload? */
+       if (le32_to_cpu(m->hdr.data_len) > 0) {
+               /* initialize page iterator */
+               con->out_msg_pos.page = 0;
+               con->out_msg_pos.page_pos =
+                       le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+               con->out_msg_pos.data_pos = 0;
+               con->out_msg_pos.did_page_crc = 0;
+               con->out_more = 1;  /* data + footer will follow */
+       } else {
+               /* no, queue up footer too and be done */
+               prepare_write_message_footer(con, v);
+       }
+
+       set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Prepare an ack.
+ */
+static void prepare_write_ack(struct ceph_connection *con)
+{
+       dout("prepare_write_ack %p %llu -> %llu\n", con,
+            con->in_seq_acked, con->in_seq);
+       con->in_seq_acked = con->in_seq;
+
+       con->out_kvec[0].iov_base = &tag_ack;
+       con->out_kvec[0].iov_len = 1;
+       con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
+       con->out_kvec[1].iov_base = &con->out_temp_ack;
+       con->out_kvec[1].iov_len = sizeof(con->out_temp_ack);
+       con->out_kvec_left = 2;
+       con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+       con->out_kvec_cur = con->out_kvec;
+       con->out_more = 1;  /* more will follow.. eventually.. */
+       set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Prepare to write keepalive byte.
+ */
+static void prepare_write_keepalive(struct ceph_connection *con)
+{
+       dout("prepare_write_keepalive %p\n", con);
+       con->out_kvec[0].iov_base = &tag_keepalive;
+       con->out_kvec[0].iov_len = 1;
+       con->out_kvec_left = 1;
+       con->out_kvec_bytes = 1;
+       con->out_kvec_cur = con->out_kvec;
+       set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Connection negotiation.
+ */
+
+static void prepare_connect_authorizer(struct ceph_connection *con)
+{
+       void *auth_buf;
+       int auth_len = 0;
+       int auth_protocol = 0;
+
+       mutex_unlock(&con->mutex);
+       if (con->ops->get_authorizer)
+               con->ops->get_authorizer(con, &auth_buf, &auth_len,
+                                        &auth_protocol, &con->auth_reply_buf,
+                                        &con->auth_reply_buf_len,
+                                        con->auth_retry);
+       mutex_lock(&con->mutex);
+
+       con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol);
+       con->out_connect.authorizer_len = cpu_to_le32(auth_len);
+
+       con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
+       con->out_kvec[con->out_kvec_left].iov_len = auth_len;
+       con->out_kvec_left++;
+       con->out_kvec_bytes += auth_len;
+}
+
+/*
+ * We connected to a peer and are saying hello.
+ */
+static void prepare_write_banner(struct ceph_messenger *msgr,
+                                struct ceph_connection *con)
+{
+       int len = strlen(CEPH_BANNER);
+
+       con->out_kvec[0].iov_base = CEPH_BANNER;
+       con->out_kvec[0].iov_len = len;
+       con->out_kvec[1].iov_base = &msgr->my_enc_addr;
+       con->out_kvec[1].iov_len = sizeof(msgr->my_enc_addr);
+       con->out_kvec_left = 2;
+       con->out_kvec_bytes = len + sizeof(msgr->my_enc_addr);
+       con->out_kvec_cur = con->out_kvec;
+       con->out_more = 0;
+       set_bit(WRITE_PENDING, &con->state);
+}
+
+static void prepare_write_connect(struct ceph_messenger *msgr,
+                                 struct ceph_connection *con,
+                                 int after_banner)
+{
+       unsigned global_seq = get_global_seq(con->msgr, 0);
+       int proto;
+
+       switch (con->peer_name.type) {
+       case CEPH_ENTITY_TYPE_MON:
+               proto = CEPH_MONC_PROTOCOL;
+               break;
+       case CEPH_ENTITY_TYPE_OSD:
+               proto = CEPH_OSDC_PROTOCOL;
+               break;
+       case CEPH_ENTITY_TYPE_MDS:
+               proto = CEPH_MDSC_PROTOCOL;
+               break;
+       default:
+               BUG();
+       }
+
+       dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con,
+            con->connect_seq, global_seq, proto);
+
+       con->out_connect.features = CEPH_FEATURE_SUPPORTED;
+       con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT);
+       con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
+       con->out_connect.global_seq = cpu_to_le32(global_seq);
+       con->out_connect.protocol_version = cpu_to_le32(proto);
+       con->out_connect.flags = 0;
+
+       if (!after_banner) {
+               con->out_kvec_left = 0;
+               con->out_kvec_bytes = 0;
+       }
+       con->out_kvec[con->out_kvec_left].iov_base = &con->out_connect;
+       con->out_kvec[con->out_kvec_left].iov_len = sizeof(con->out_connect);
+       con->out_kvec_left++;
+       con->out_kvec_bytes += sizeof(con->out_connect);
+       con->out_kvec_cur = con->out_kvec;
+       con->out_more = 0;
+       set_bit(WRITE_PENDING, &con->state);
+
+       prepare_connect_authorizer(con);
+}
+
+
+/*
+ * write as much of pending kvecs to the socket as we can.
+ *  1 -> done
+ *  0 -> socket full, but more to do
+ * <0 -> error
+ */
+static int write_partial_kvec(struct ceph_connection *con)
+{
+       int ret;
+
+       dout("write_partial_kvec %p %d left\n", con, con->out_kvec_bytes);
+       while (con->out_kvec_bytes > 0) {
+               ret = ceph_tcp_sendmsg(con->sock, con->out_kvec_cur,
+                                      con->out_kvec_left, con->out_kvec_bytes,
+                                      con->out_more);
+               if (ret <= 0)
+                       goto out;
+               con->out_kvec_bytes -= ret;
+               if (con->out_kvec_bytes == 0)
+                       break;            /* done */
+               while (ret > 0) {
+                       if (ret >= con->out_kvec_cur->iov_len) {
+                               ret -= con->out_kvec_cur->iov_len;
+                               con->out_kvec_cur++;
+                               con->out_kvec_left--;
+                       } else {
+                               con->out_kvec_cur->iov_len -= ret;
+                               con->out_kvec_cur->iov_base += ret;
+                               ret = 0;
+                               break;
+                       }
+               }
+       }
+       con->out_kvec_left = 0;
+       con->out_kvec_is_msg = false;
+       ret = 1;
+out:
+       dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con,
+            con->out_kvec_bytes, con->out_kvec_left, ret);
+       return ret;  /* done! */
+}
+
+/*
+ * Write as much message data payload as we can.  If we finish, queue
+ * up the footer.
+ *  1 -> done, footer is now queued in out_kvec[].
+ *  0 -> socket full, but more to do
+ * <0 -> error
+ */
+static int write_partial_msg_pages(struct ceph_connection *con)
+{
+       struct ceph_msg *msg = con->out_msg;
+       unsigned data_len = le32_to_cpu(msg->hdr.data_len);
+       size_t len;
+       int crc = con->msgr->nocrc;
+       int ret;
+
+       dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n",
+            con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages,
+            con->out_msg_pos.page_pos);
+
+       while (con->out_msg_pos.page < con->out_msg->nr_pages) {
+               struct page *page = NULL;
+               void *kaddr = NULL;
+
+               /*
+                * if we are calculating the data crc (the default), we need
+                * to map the page.  if our pages[] has been revoked, use the
+                * zero page.
+                */
+               if (msg->pages) {
+                       page = msg->pages[con->out_msg_pos.page];
+                       if (crc)
+                               kaddr = kmap(page);
+               } else if (msg->pagelist) {
+                       page = list_first_entry(&msg->pagelist->head,
+                                               struct page, lru);
+                       if (crc)
+                               kaddr = kmap(page);
+               } else {
+                       page = con->msgr->zero_page;
+                       if (crc)
+                               kaddr = page_address(con->msgr->zero_page);
+               }
+               len = min((int)(PAGE_SIZE - con->out_msg_pos.page_pos),
+                         (int)(data_len - con->out_msg_pos.data_pos));
+               if (crc && !con->out_msg_pos.did_page_crc) {
+                       void *base = kaddr + con->out_msg_pos.page_pos;
+                       u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
+
+                       BUG_ON(kaddr == NULL);
+                       con->out_msg->footer.data_crc =
+                               cpu_to_le32(crc32c(tmpcrc, base, len));
+                       con->out_msg_pos.did_page_crc = 1;
+               }
+
+               ret = kernel_sendpage(con->sock, page,
+                                     con->out_msg_pos.page_pos, len,
+                                     MSG_DONTWAIT | MSG_NOSIGNAL |
+                                     MSG_MORE);
+
+               if (crc && (msg->pages || msg->pagelist))
+                       kunmap(page);
+
+               if (ret <= 0)
+                       goto out;
+
+               con->out_msg_pos.data_pos += ret;
+               con->out_msg_pos.page_pos += ret;
+               if (ret == len) {
+                       con->out_msg_pos.page_pos = 0;
+                       con->out_msg_pos.page++;
+                       con->out_msg_pos.did_page_crc = 0;
+                       if (msg->pagelist)
+                               list_move_tail(&page->lru,
+                                              &msg->pagelist->head);
+               }
+       }
+
+       dout("write_partial_msg_pages %p msg %p done\n", con, msg);
+
+       /* prepare and queue up footer, too */
+       if (!crc)
+               con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
+       con->out_kvec_bytes = 0;
+       con->out_kvec_left = 0;
+       con->out_kvec_cur = con->out_kvec;
+       prepare_write_message_footer(con, 0);
+       ret = 1;
+out:
+       return ret;
+}
+
+/*
+ * write some zeros
+ */
+static int write_partial_skip(struct ceph_connection *con)
+{
+       int ret;
+
+       while (con->out_skip > 0) {
+               struct kvec iov = {
+                       .iov_base = page_address(con->msgr->zero_page),
+                       .iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE)
+               };
+
+               ret = ceph_tcp_sendmsg(con->sock, &iov, 1, iov.iov_len, 1);
+               if (ret <= 0)
+                       goto out;
+               con->out_skip -= ret;
+       }
+       ret = 1;
+out:
+       return ret;
+}
+
+/*
+ * Prepare to read connection handshake, or an ack.
+ */
+static void prepare_read_banner(struct ceph_connection *con)
+{
+       dout("prepare_read_banner %p\n", con);
+       con->in_base_pos = 0;
+}
+
+static void prepare_read_connect(struct ceph_connection *con)
+{
+       dout("prepare_read_connect %p\n", con);
+       con->in_base_pos = 0;
+}
+
+static void prepare_read_connect_retry(struct ceph_connection *con)
+{
+       dout("prepare_read_connect_retry %p\n", con);
+       con->in_base_pos = strlen(CEPH_BANNER) + sizeof(con->actual_peer_addr)
+               + sizeof(con->peer_addr_for_me);
+}
+
+static void prepare_read_ack(struct ceph_connection *con)
+{
+       dout("prepare_read_ack %p\n", con);
+       con->in_base_pos = 0;
+}
+
+static void prepare_read_tag(struct ceph_connection *con)
+{
+       dout("prepare_read_tag %p\n", con);
+       con->in_base_pos = 0;
+       con->in_tag = CEPH_MSGR_TAG_READY;
+}
+
+/*
+ * Prepare to read a message.
+ */
+static int prepare_read_message(struct ceph_connection *con)
+{
+       dout("prepare_read_message %p\n", con);
+       BUG_ON(con->in_msg != NULL);
+       con->in_base_pos = 0;
+       con->in_front_crc = con->in_middle_crc = con->in_data_crc = 0;
+       return 0;
+}
+
+
+static int read_partial(struct ceph_connection *con,
+                       int *to, int size, void *object)
+{
+       *to += size;
+       while (con->in_base_pos < *to) {
+               int left = *to - con->in_base_pos;
+               int have = size - left;
+               int ret = ceph_tcp_recvmsg(con->sock, object + have, left);
+               if (ret <= 0)
+                       return ret;
+               con->in_base_pos += ret;
+       }
+       return 1;
+}
+
+
+/*
+ * Read all or part of the connect-side handshake on a new connection
+ */
+static int read_partial_banner(struct ceph_connection *con)
+{
+       int ret, to = 0;
+
+       dout("read_partial_banner %p at %d\n", con, con->in_base_pos);
+
+       /* peer's banner */
+       ret = read_partial(con, &to, strlen(CEPH_BANNER), con->in_banner);
+       if (ret <= 0)
+               goto out;
+       ret = read_partial(con, &to, sizeof(con->actual_peer_addr),
+                          &con->actual_peer_addr);
+       if (ret <= 0)
+               goto out;
+       ret = read_partial(con, &to, sizeof(con->peer_addr_for_me),
+                          &con->peer_addr_for_me);
+       if (ret <= 0)
+               goto out;
+out:
+       return ret;
+}
+
+static int read_partial_connect(struct ceph_connection *con)
+{
+       int ret, to = 0;
+
+       dout("read_partial_connect %p at %d\n", con, con->in_base_pos);
+
+       ret = read_partial(con, &to, sizeof(con->in_reply), &con->in_reply);
+       if (ret <= 0)
+               goto out;
+       ret = read_partial(con, &to, le32_to_cpu(con->in_reply.authorizer_len),
+                          con->auth_reply_buf);
+       if (ret <= 0)
+               goto out;
+
+       dout("read_partial_connect %p tag %d, con_seq = %u, g_seq = %u\n",
+            con, (int)con->in_reply.tag,
+            le32_to_cpu(con->in_reply.connect_seq),
+            le32_to_cpu(con->in_reply.global_seq));
+out:
+       return ret;
+
+}
+
+/*
+ * Verify the hello banner looks okay.
+ */
+static int verify_hello(struct ceph_connection *con)
+{
+       if (memcmp(con->in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) {
+               pr_err("connect to %s got bad banner\n",
+                      pr_addr(&con->peer_addr.in_addr));
+               con->error_msg = "protocol error, bad banner";
+               return -1;
+       }
+       return 0;
+}
+
+static bool addr_is_blank(struct sockaddr_storage *ss)
+{
+       switch (ss->ss_family) {
+       case AF_INET:
+               return ((struct sockaddr_in *)ss)->sin_addr.s_addr == 0;
+       case AF_INET6:
+               return
+                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[0] == 0 &&
+                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[1] == 0 &&
+                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[2] == 0 &&
+                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[3] == 0;
+       }
+       return false;
+}
+
+static int addr_port(struct sockaddr_storage *ss)
+{
+       switch (ss->ss_family) {
+       case AF_INET:
+               return ntohs(((struct sockaddr_in *)ss)->sin_port);
+       case AF_INET6:
+               return ntohs(((struct sockaddr_in6 *)ss)->sin6_port);
+       }
+       return 0;
+}
+
+static void addr_set_port(struct sockaddr_storage *ss, int p)
+{
+       switch (ss->ss_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)ss)->sin_port = htons(p);
+       case AF_INET6:
+               ((struct sockaddr_in6 *)ss)->sin6_port = htons(p);
+       }
+}
+
+/*
+ * Parse an ip[:port] list into an addr array.  Use the default
+ * monitor port if a port isn't specified.
+ */
+int ceph_parse_ips(const char *c, const char *end,
+                  struct ceph_entity_addr *addr,
+                  int max_count, int *count)
+{
+       int i;
+       const char *p = c;
+
+       dout("parse_ips on '%.*s'\n", (int)(end-c), c);
+       for (i = 0; i < max_count; i++) {
+               const char *ipend;
+               struct sockaddr_storage *ss = &addr[i].in_addr;
+               struct sockaddr_in *in4 = (void *)ss;
+               struct sockaddr_in6 *in6 = (void *)ss;
+               int port;
+
+               memset(ss, 0, sizeof(*ss));
+               if (in4_pton(p, end - p, (u8 *)&in4->sin_addr.s_addr,
+                            ',', &ipend)) {
+                       ss->ss_family = AF_INET;
+               } else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
+                                   ',', &ipend)) {
+                       ss->ss_family = AF_INET6;
+               } else {
+                       goto bad;
+               }
+               p = ipend;
+
+               /* port? */
+               if (p < end && *p == ':') {
+                       port = 0;
+                       p++;
+                       while (p < end && *p >= '0' && *p <= '9') {
+                               port = (port * 10) + (*p - '0');
+                               p++;
+                       }
+                       if (port > 65535 || port == 0)
+                               goto bad;
+               } else {
+                       port = CEPH_MON_PORT;
+               }
+
+               addr_set_port(ss, port);
+
+               dout("parse_ips got %s\n", pr_addr(ss));
+
+               if (p == end)
+                       break;
+               if (*p != ',')
+                       goto bad;
+               p++;
+       }
+
+       if (p != end)
+               goto bad;
+
+       if (count)
+               *count = i + 1;
+       return 0;
+
+bad:
+       pr_err("parse_ips bad ip '%s'\n", c);
+       return -EINVAL;
+}
+
+static int process_banner(struct ceph_connection *con)
+{
+       dout("process_banner on %p\n", con);
+
+       if (verify_hello(con) < 0)
+               return -1;
+
+       ceph_decode_addr(&con->actual_peer_addr);
+       ceph_decode_addr(&con->peer_addr_for_me);
+
+       /*
+        * Make sure the other end is who we wanted.  note that the other
+        * end may not yet know their ip address, so if it's 0.0.0.0, give
+        * them the benefit of the doubt.
+        */
+       if (memcmp(&con->peer_addr, &con->actual_peer_addr,
+                  sizeof(con->peer_addr)) != 0 &&
+           !(addr_is_blank(&con->actual_peer_addr.in_addr) &&
+             con->actual_peer_addr.nonce == con->peer_addr.nonce)) {
+               pr_warning("wrong peer, want %s/%lld, got %s/%lld\n",
+                          pr_addr(&con->peer_addr.in_addr),
+                          le64_to_cpu(con->peer_addr.nonce),
+                          pr_addr(&con->actual_peer_addr.in_addr),
+                          le64_to_cpu(con->actual_peer_addr.nonce));
+               con->error_msg = "wrong peer at address";
+               return -1;
+       }
+
+       /*
+        * did we learn our address?
+        */
+       if (addr_is_blank(&con->msgr->inst.addr.in_addr)) {
+               int port = addr_port(&con->msgr->inst.addr.in_addr);
+
+               memcpy(&con->msgr->inst.addr.in_addr,
+                      &con->peer_addr_for_me.in_addr,
+                      sizeof(con->peer_addr_for_me.in_addr));
+               addr_set_port(&con->msgr->inst.addr.in_addr, port);
+               encode_my_addr(con->msgr);
+               dout("process_banner learned my addr is %s\n",
+                    pr_addr(&con->msgr->inst.addr.in_addr));
+       }
+
+       set_bit(NEGOTIATING, &con->state);
+       prepare_read_connect(con);
+       return 0;
+}
+
+static void fail_protocol(struct ceph_connection *con)
+{
+       reset_connection(con);
+       set_bit(CLOSED, &con->state);  /* in case there's queued work */
+
+       mutex_unlock(&con->mutex);
+       if (con->ops->bad_proto)
+               con->ops->bad_proto(con);
+       mutex_lock(&con->mutex);
+}
+
+static int process_connect(struct ceph_connection *con)
+{
+       u64 sup_feat = CEPH_FEATURE_SUPPORTED;
+       u64 req_feat = CEPH_FEATURE_REQUIRED;
+       u64 server_feat = le64_to_cpu(con->in_reply.features);
+
+       dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
+
+       switch (con->in_reply.tag) {
+       case CEPH_MSGR_TAG_FEATURES:
+               pr_err("%s%lld %s feature set mismatch,"
+                      " my %llx < server's %llx, missing %llx\n",
+                      ENTITY_NAME(con->peer_name),
+                      pr_addr(&con->peer_addr.in_addr),
+                      sup_feat, server_feat, server_feat & ~sup_feat);
+               con->error_msg = "missing required protocol features";
+               fail_protocol(con);
+               return -1;
+
+       case CEPH_MSGR_TAG_BADPROTOVER:
+               pr_err("%s%lld %s protocol version mismatch,"
+                      " my %d != server's %d\n",
+                      ENTITY_NAME(con->peer_name),
+                      pr_addr(&con->peer_addr.in_addr),
+                      le32_to_cpu(con->out_connect.protocol_version),
+                      le32_to_cpu(con->in_reply.protocol_version));
+               con->error_msg = "protocol version mismatch";
+               fail_protocol(con);
+               return -1;
+
+       case CEPH_MSGR_TAG_BADAUTHORIZER:
+               con->auth_retry++;
+               dout("process_connect %p got BADAUTHORIZER attempt %d\n", con,
+                    con->auth_retry);
+               if (con->auth_retry == 2) {
+                       con->error_msg = "connect authorization failure";
+                       reset_connection(con);
+                       set_bit(CLOSED, &con->state);
+                       return -1;
+               }
+               con->auth_retry = 1;
+               prepare_write_connect(con->msgr, con, 0);
+               prepare_read_connect_retry(con);
+               break;
+
+       case CEPH_MSGR_TAG_RESETSESSION:
+               /*
+                * If we connected with a large connect_seq but the peer
+                * has no record of a session with us (no connection, or
+                * connect_seq == 0), they will send RESETSESION to indicate
+                * that they must have reset their session, and may have
+                * dropped messages.
+                */
+               dout("process_connect got RESET peer seq %u\n",
+                    le32_to_cpu(con->in_connect.connect_seq));
+               pr_err("%s%lld %s connection reset\n",
+                      ENTITY_NAME(con->peer_name),
+                      pr_addr(&con->peer_addr.in_addr));
+               reset_connection(con);
+               prepare_write_connect(con->msgr, con, 0);
+               prepare_read_connect(con);
+
+               /* Tell ceph about it. */
+               mutex_unlock(&con->mutex);
+               pr_info("reset on %s%lld\n", ENTITY_NAME(con->peer_name));
+               if (con->ops->peer_reset)
+                       con->ops->peer_reset(con);
+               mutex_lock(&con->mutex);
+               break;
+
+       case CEPH_MSGR_TAG_RETRY_SESSION:
+               /*
+                * If we sent a smaller connect_seq than the peer has, try
+                * again with a larger value.
+                */
+               dout("process_connect got RETRY my seq = %u, peer_seq = %u\n",
+                    le32_to_cpu(con->out_connect.connect_seq),
+                    le32_to_cpu(con->in_connect.connect_seq));
+               con->connect_seq = le32_to_cpu(con->in_connect.connect_seq);
+               prepare_write_connect(con->msgr, con, 0);
+               prepare_read_connect(con);
+               break;
+
+       case CEPH_MSGR_TAG_RETRY_GLOBAL:
+               /*
+                * If we sent a smaller global_seq than the peer has, try
+                * again with a larger value.
+                */
+               dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n",
+                    con->peer_global_seq,
+                    le32_to_cpu(con->in_connect.global_seq));
+               get_global_seq(con->msgr,
+                              le32_to_cpu(con->in_connect.global_seq));
+               prepare_write_connect(con->msgr, con, 0);
+               prepare_read_connect(con);
+               break;
+
+       case CEPH_MSGR_TAG_READY:
+               if (req_feat & ~server_feat) {
+                       pr_err("%s%lld %s protocol feature mismatch,"
+                              " my required %llx > server's %llx, need %llx\n",
+                              ENTITY_NAME(con->peer_name),
+                              pr_addr(&con->peer_addr.in_addr),
+                              req_feat, server_feat, req_feat & ~server_feat);
+                       con->error_msg = "missing required protocol features";
+                       fail_protocol(con);
+                       return -1;
+               }
+               clear_bit(CONNECTING, &con->state);
+               con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq);
+               con->connect_seq++;
+               dout("process_connect got READY gseq %d cseq %d (%d)\n",
+                    con->peer_global_seq,
+                    le32_to_cpu(con->in_reply.connect_seq),
+                    con->connect_seq);
+               WARN_ON(con->connect_seq !=
+                       le32_to_cpu(con->in_reply.connect_seq));
+
+               if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY)
+                       set_bit(LOSSYTX, &con->state);
+
+               prepare_read_tag(con);
+               break;
+
+       case CEPH_MSGR_TAG_WAIT:
+               /*
+                * If there is a connection race (we are opening
+                * connections to each other), one of us may just have
+                * to WAIT.  This shouldn't happen if we are the
+                * client.
+                */
+               pr_err("process_connect peer connecting WAIT\n");
+
+       default:
+               pr_err("connect protocol error, will retry\n");
+               con->error_msg = "protocol error, garbage tag during connect";
+               return -1;
+       }
+       return 0;
+}
+
+
+/*
+ * read (part of) an ack
+ */
+static int read_partial_ack(struct ceph_connection *con)
+{
+       int to = 0;
+
+       return read_partial(con, &to, sizeof(con->in_temp_ack),
+                           &con->in_temp_ack);
+}
+
+
+/*
+ * We can finally discard anything that's been acked.
+ */
+static void process_ack(struct ceph_connection *con)
+{
+       struct ceph_msg *m;
+       u64 ack = le64_to_cpu(con->in_temp_ack);
+       u64 seq;
+
+       while (!list_empty(&con->out_sent)) {
+               m = list_first_entry(&con->out_sent, struct ceph_msg,
+                                    list_head);
+               seq = le64_to_cpu(m->hdr.seq);
+               if (seq > ack)
+                       break;
+               dout("got ack for seq %llu type %d at %p\n", seq,
+                    le16_to_cpu(m->hdr.type), m);
+               ceph_msg_remove(m);
+       }
+       prepare_read_tag(con);
+}
+
+
+
+
+static int read_partial_message_section(struct ceph_connection *con,
+                                       struct kvec *section, unsigned int sec_len,
+                                       u32 *crc)
+{
+       int left;
+       int ret;
+
+       BUG_ON(!section);
+
+       while (section->iov_len < sec_len) {
+               BUG_ON(section->iov_base == NULL);
+               left = sec_len - section->iov_len;
+               ret = ceph_tcp_recvmsg(con->sock, (char *)section->iov_base +
+                                      section->iov_len, left);
+               if (ret <= 0)
+                       return ret;
+               section->iov_len += ret;
+               if (section->iov_len == sec_len)
+                       *crc = crc32c(0, section->iov_base,
+                                     section->iov_len);
+       }
+
+       return 1;
+}
+
+static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
+                               struct ceph_msg_header *hdr,
+                               int *skip);
+/*
+ * read (part of) a message.
+ */
+static int read_partial_message(struct ceph_connection *con)
+{
+       struct ceph_msg *m = con->in_msg;
+       void *p;
+       int ret;
+       int to, left;
+       unsigned front_len, middle_len, data_len, data_off;
+       int datacrc = con->msgr->nocrc;
+       int skip;
+
+       dout("read_partial_message con %p msg %p\n", con, m);
+
+       /* header */
+       while (con->in_base_pos < sizeof(con->in_hdr)) {
+               left = sizeof(con->in_hdr) - con->in_base_pos;
+               ret = ceph_tcp_recvmsg(con->sock,
+                                      (char *)&con->in_hdr + con->in_base_pos,
+                                      left);
+               if (ret <= 0)
+                       return ret;
+               con->in_base_pos += ret;
+               if (con->in_base_pos == sizeof(con->in_hdr)) {
+                       u32 crc = crc32c(0, (void *)&con->in_hdr,
+                                sizeof(con->in_hdr) - sizeof(con->in_hdr.crc));
+                       if (crc != le32_to_cpu(con->in_hdr.crc)) {
+                               pr_err("read_partial_message bad hdr "
+                                      " crc %u != expected %u\n",
+                                      crc, con->in_hdr.crc);
+                               return -EBADMSG;
+                       }
+               }
+       }
+       front_len = le32_to_cpu(con->in_hdr.front_len);
+       if (front_len > CEPH_MSG_MAX_FRONT_LEN)
+               return -EIO;
+       middle_len = le32_to_cpu(con->in_hdr.middle_len);
+       if (middle_len > CEPH_MSG_MAX_DATA_LEN)
+               return -EIO;
+       data_len = le32_to_cpu(con->in_hdr.data_len);
+       if (data_len > CEPH_MSG_MAX_DATA_LEN)
+               return -EIO;
+       data_off = le16_to_cpu(con->in_hdr.data_off);
+
+       /* allocate message? */
+       if (!con->in_msg) {
+               dout("got hdr type %d front %d data %d\n", con->in_hdr.type,
+                    con->in_hdr.front_len, con->in_hdr.data_len);
+               con->in_msg = ceph_alloc_msg(con, &con->in_hdr, &skip);
+               if (skip) {
+                       /* skip this message */
+                       dout("alloc_msg returned NULL, skipping message\n");
+                       con->in_base_pos = -front_len - middle_len - data_len -
+                               sizeof(m->footer);
+                       con->in_tag = CEPH_MSGR_TAG_READY;
+                       return 0;
+               }
+               if (IS_ERR(con->in_msg)) {
+                       ret = PTR_ERR(con->in_msg);
+                       con->in_msg = NULL;
+                       con->error_msg =
+                               "error allocating memory for incoming message";
+                       return ret;
+               }
+               m = con->in_msg;
+               m->front.iov_len = 0;    /* haven't read it yet */
+               if (m->middle)
+                       m->middle->vec.iov_len = 0;
+
+               con->in_msg_pos.page = 0;
+               con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+               con->in_msg_pos.data_pos = 0;
+       }
+
+       /* front */
+       ret = read_partial_message_section(con, &m->front, front_len,
+                                          &con->in_front_crc);
+       if (ret <= 0)
+               return ret;
+
+       /* middle */
+       if (m->middle) {
+               ret = read_partial_message_section(con, &m->middle->vec, middle_len,
+                                                  &con->in_middle_crc);
+               if (ret <= 0)
+                       return ret;
+       }
+
+       /* (page) data */
+       while (con->in_msg_pos.data_pos < data_len) {
+               left = min((int)(data_len - con->in_msg_pos.data_pos),
+                          (int)(PAGE_SIZE - con->in_msg_pos.page_pos));
+               BUG_ON(m->pages == NULL);
+               p = kmap(m->pages[con->in_msg_pos.page]);
+               ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
+                                      left);
+               if (ret > 0 && datacrc)
+                       con->in_data_crc =
+                               crc32c(con->in_data_crc,
+                                         p + con->in_msg_pos.page_pos, ret);
+               kunmap(m->pages[con->in_msg_pos.page]);
+               if (ret <= 0)
+                       return ret;
+               con->in_msg_pos.data_pos += ret;
+               con->in_msg_pos.page_pos += ret;
+               if (con->in_msg_pos.page_pos == PAGE_SIZE) {
+                       con->in_msg_pos.page_pos = 0;
+                       con->in_msg_pos.page++;
+               }
+       }
+
+       /* footer */
+       to = sizeof(m->hdr) + sizeof(m->footer);
+       while (con->in_base_pos < to) {
+               left = to - con->in_base_pos;
+               ret = ceph_tcp_recvmsg(con->sock, (char *)&m->footer +
+                                      (con->in_base_pos - sizeof(m->hdr)),
+                                      left);
+               if (ret <= 0)
+                       return ret;
+               con->in_base_pos += ret;
+       }
+       dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n",
+            m, front_len, m->footer.front_crc, middle_len,
+            m->footer.middle_crc, data_len, m->footer.data_crc);
+
+       /* crc ok? */
+       if (con->in_front_crc != le32_to_cpu(m->footer.front_crc)) {
+               pr_err("read_partial_message %p front crc %u != exp. %u\n",
+                      m, con->in_front_crc, m->footer.front_crc);
+               return -EBADMSG;
+       }
+       if (con->in_middle_crc != le32_to_cpu(m->footer.middle_crc)) {
+               pr_err("read_partial_message %p middle crc %u != exp %u\n",
+                      m, con->in_middle_crc, m->footer.middle_crc);
+               return -EBADMSG;
+       }
+       if (datacrc &&
+           (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 &&
+           con->in_data_crc != le32_to_cpu(m->footer.data_crc)) {
+               pr_err("read_partial_message %p data crc %u != exp. %u\n", m,
+                      con->in_data_crc, le32_to_cpu(m->footer.data_crc));
+               return -EBADMSG;
+       }
+
+       return 1; /* done! */
+}
+
+/*
+ * Process message.  This happens in the worker thread.  The callback should
+ * be careful not to do anything that waits on other incoming messages or it
+ * may deadlock.
+ */
+static void process_message(struct ceph_connection *con)
+{
+       struct ceph_msg *msg;
+
+       msg = con->in_msg;
+       con->in_msg = NULL;
+
+       /* if first message, set peer_name */
+       if (con->peer_name.type == 0)
+               con->peer_name = msg->hdr.src.name;
+
+       con->in_seq++;
+       mutex_unlock(&con->mutex);
+
+       dout("===== %p %llu from %s%lld %d=%s len %d+%d (%u %u %u) =====\n",
+            msg, le64_to_cpu(msg->hdr.seq),
+            ENTITY_NAME(msg->hdr.src.name),
+            le16_to_cpu(msg->hdr.type),
+            ceph_msg_type_name(le16_to_cpu(msg->hdr.type)),
+            le32_to_cpu(msg->hdr.front_len),
+            le32_to_cpu(msg->hdr.data_len),
+            con->in_front_crc, con->in_middle_crc, con->in_data_crc);
+       con->ops->dispatch(con, msg);
+
+       mutex_lock(&con->mutex);
+       prepare_read_tag(con);
+}
+
+
+/*
+ * Write something to the socket.  Called in a worker thread when the
+ * socket appears to be writeable and we have something ready to send.
+ */
+static int try_write(struct ceph_connection *con)
+{
+       struct ceph_messenger *msgr = con->msgr;
+       int ret = 1;
+
+       dout("try_write start %p state %lu nref %d\n", con, con->state,
+            atomic_read(&con->nref));
+
+       mutex_lock(&con->mutex);
+more:
+       dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
+
+       /* open the socket first? */
+       if (con->sock == NULL) {
+               /*
+                * if we were STANDBY and are reconnecting _this_
+                * connection, bump connect_seq now.  Always bump
+                * global_seq.
+                */
+               if (test_and_clear_bit(STANDBY, &con->state))
+                       con->connect_seq++;
+
+               prepare_write_banner(msgr, con);
+               prepare_write_connect(msgr, con, 1);
+               prepare_read_banner(con);
+               set_bit(CONNECTING, &con->state);
+               clear_bit(NEGOTIATING, &con->state);
+
+               BUG_ON(con->in_msg);
+               con->in_tag = CEPH_MSGR_TAG_READY;
+               dout("try_write initiating connect on %p new state %lu\n",
+                    con, con->state);
+               con->sock = ceph_tcp_connect(con);
+               if (IS_ERR(con->sock)) {
+                       con->sock = NULL;
+                       con->error_msg = "connect error";
+                       ret = -1;
+                       goto out;
+               }
+       }
+
+more_kvec:
+       /* kvec data queued? */
+       if (con->out_skip) {
+               ret = write_partial_skip(con);
+               if (ret <= 0)
+                       goto done;
+               if (ret < 0) {
+                       dout("try_write write_partial_skip err %d\n", ret);
+                       goto done;
+               }
+       }
+       if (con->out_kvec_left) {
+               ret = write_partial_kvec(con);
+               if (ret <= 0)
+                       goto done;
+       }
+
+       /* msg pages? */
+       if (con->out_msg) {
+               if (con->out_msg_done) {
+                       ceph_msg_put(con->out_msg);
+                       con->out_msg = NULL;   /* we're done with this one */
+                       goto do_next;
+               }
+
+               ret = write_partial_msg_pages(con);
+               if (ret == 1)
+                       goto more_kvec;  /* we need to send the footer, too! */
+               if (ret == 0)
+                       goto done;
+               if (ret < 0) {
+                       dout("try_write write_partial_msg_pages err %d\n",
+                            ret);
+                       goto done;
+               }
+       }
+
+do_next:
+       if (!test_bit(CONNECTING, &con->state)) {
+               /* is anything else pending? */
+               if (!list_empty(&con->out_queue)) {
+                       prepare_write_message(con);
+                       goto more;
+               }
+               if (con->in_seq > con->in_seq_acked) {
+                       prepare_write_ack(con);
+                       goto more;
+               }
+               if (test_and_clear_bit(KEEPALIVE_PENDING, &con->state)) {
+                       prepare_write_keepalive(con);
+                       goto more;
+               }
+       }
+
+       /* Nothing to do! */
+       clear_bit(WRITE_PENDING, &con->state);
+       dout("try_write nothing else to write.\n");
+done:
+       ret = 0;
+out:
+       mutex_unlock(&con->mutex);
+       dout("try_write done on %p\n", con);
+       return ret;
+}
+
+
+
+/*
+ * Read what we can from the socket.
+ */
+static int try_read(struct ceph_connection *con)
+{
+       struct ceph_messenger *msgr;
+       int ret = -1;
+
+       if (!con->sock)
+               return 0;
+
+       if (test_bit(STANDBY, &con->state))
+               return 0;
+
+       dout("try_read start on %p\n", con);
+       msgr = con->msgr;
+
+       mutex_lock(&con->mutex);
+
+more:
+       dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
+            con->in_base_pos);
+       if (test_bit(CONNECTING, &con->state)) {
+               if (!test_bit(NEGOTIATING, &con->state)) {
+                       dout("try_read connecting\n");
+                       ret = read_partial_banner(con);
+                       if (ret <= 0)
+                               goto done;
+                       if (process_banner(con) < 0) {
+                               ret = -1;
+                               goto out;
+                       }
+               }
+               ret = read_partial_connect(con);
+               if (ret <= 0)
+                       goto done;
+               if (process_connect(con) < 0) {
+                       ret = -1;
+                       goto out;
+               }
+               goto more;
+       }
+
+       if (con->in_base_pos < 0) {
+               /*
+                * skipping + discarding content.
+                *
+                * FIXME: there must be a better way to do this!
+                */
+               static char buf[1024];
+               int skip = min(1024, -con->in_base_pos);
+               dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
+               ret = ceph_tcp_recvmsg(con->sock, buf, skip);
+               if (ret <= 0)
+                       goto done;
+               con->in_base_pos += ret;
+               if (con->in_base_pos)
+                       goto more;
+       }
+       if (con->in_tag == CEPH_MSGR_TAG_READY) {
+               /*
+                * what's next?
+                */
+               ret = ceph_tcp_recvmsg(con->sock, &con->in_tag, 1);
+               if (ret <= 0)
+                       goto done;
+               dout("try_read got tag %d\n", (int)con->in_tag);
+               switch (con->in_tag) {
+               case CEPH_MSGR_TAG_MSG:
+                       prepare_read_message(con);
+                       break;
+               case CEPH_MSGR_TAG_ACK:
+                       prepare_read_ack(con);
+                       break;
+               case CEPH_MSGR_TAG_CLOSE:
+                       set_bit(CLOSED, &con->state);   /* fixme */
+                       goto done;
+               default:
+                       goto bad_tag;
+               }
+       }
+       if (con->in_tag == CEPH_MSGR_TAG_MSG) {
+               ret = read_partial_message(con);
+               if (ret <= 0) {
+                       switch (ret) {
+                       case -EBADMSG:
+                               con->error_msg = "bad crc";
+                               ret = -EIO;
+                               goto out;
+                       case -EIO:
+                               con->error_msg = "io error";
+                               goto out;
+                       default:
+                               goto done;
+                       }
+               }
+               if (con->in_tag == CEPH_MSGR_TAG_READY)
+                       goto more;
+               process_message(con);
+               goto more;
+       }
+       if (con->in_tag == CEPH_MSGR_TAG_ACK) {
+               ret = read_partial_ack(con);
+               if (ret <= 0)
+                       goto done;
+               process_ack(con);
+               goto more;
+       }
+
+done:
+       ret = 0;
+out:
+       mutex_unlock(&con->mutex);
+       dout("try_read done on %p\n", con);
+       return ret;
+
+bad_tag:
+       pr_err("try_read bad con->in_tag = %d\n", (int)con->in_tag);
+       con->error_msg = "protocol error, garbage tag";
+       ret = -1;
+       goto out;
+}
+
+
+/*
+ * Atomically queue work on a connection.  Bump @con reference to
+ * avoid races with connection teardown.
+ *
+ * There is some trickery going on with QUEUED and BUSY because we
+ * only want a _single_ thread operating on each connection at any
+ * point in time, but we want to use all available CPUs.
+ *
+ * The worker thread only proceeds if it can atomically set BUSY.  It
+ * clears QUEUED and does it's thing.  When it thinks it's done, it
+ * clears BUSY, then rechecks QUEUED.. if it's set again, it loops
+ * (tries again to set BUSY).
+ *
+ * To queue work, we first set QUEUED, _then_ if BUSY isn't set, we
+ * try to queue work.  If that fails (work is already queued, or BUSY)
+ * we give up (work also already being done or is queued) but leave QUEUED
+ * set so that the worker thread will loop if necessary.
+ */
+static void queue_con(struct ceph_connection *con)
+{
+       if (test_bit(DEAD, &con->state)) {
+               dout("queue_con %p ignoring: DEAD\n",
+                    con);
+               return;
+       }
+
+       if (!con->ops->get(con)) {
+               dout("queue_con %p ref count 0\n", con);
+               return;
+       }
+
+       set_bit(QUEUED, &con->state);
+       if (test_bit(BUSY, &con->state)) {
+               dout("queue_con %p - already BUSY\n", con);
+               con->ops->put(con);
+       } else if (!queue_work(ceph_msgr_wq, &con->work.work)) {
+               dout("queue_con %p - already queued\n", con);
+               con->ops->put(con);
+       } else {
+               dout("queue_con %p\n", con);
+       }
+}
+
+/*
+ * Do some work on a connection.  Drop a connection ref when we're done.
+ */
+static void con_work(struct work_struct *work)
+{
+       struct ceph_connection *con = container_of(work, struct ceph_connection,
+                                                  work.work);
+       int backoff = 0;
+
+more:
+       if (test_and_set_bit(BUSY, &con->state) != 0) {
+               dout("con_work %p BUSY already set\n", con);
+               goto out;
+       }
+       dout("con_work %p start, clearing QUEUED\n", con);
+       clear_bit(QUEUED, &con->state);
+
+       if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
+               dout("con_work CLOSED\n");
+               con_close_socket(con);
+               goto done;
+       }
+       if (test_and_clear_bit(OPENING, &con->state)) {
+               /* reopen w/ new peer */
+               dout("con_work OPENING\n");
+               con_close_socket(con);
+       }
+
+       if (test_and_clear_bit(SOCK_CLOSED, &con->state) ||
+           try_read(con) < 0 ||
+           try_write(con) < 0) {
+               backoff = 1;
+               ceph_fault(con);     /* error/fault path */
+       }
+
+done:
+       clear_bit(BUSY, &con->state);
+       dout("con->state=%lu\n", con->state);
+       if (test_bit(QUEUED, &con->state)) {
+               if (!backoff || test_bit(OPENING, &con->state)) {
+                       dout("con_work %p QUEUED reset, looping\n", con);
+                       goto more;
+               }
+               dout("con_work %p QUEUED reset, but just faulted\n", con);
+               clear_bit(QUEUED, &con->state);
+       }
+       dout("con_work %p done\n", con);
+
+out:
+       con->ops->put(con);
+}
+
+
+/*
+ * Generic error/fault handler.  A retry mechanism is used with
+ * exponential backoff
+ */
+static void ceph_fault(struct ceph_connection *con)
+{
+       pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
+              pr_addr(&con->peer_addr.in_addr), con->error_msg);
+       dout("fault %p state %lu to peer %s\n",
+            con, con->state, pr_addr(&con->peer_addr.in_addr));
+
+       if (test_bit(LOSSYTX, &con->state)) {
+               dout("fault on LOSSYTX channel\n");
+               goto out;
+       }
+
+       clear_bit(BUSY, &con->state);  /* to avoid an improbable race */
+
+       mutex_lock(&con->mutex);
+       if (test_bit(CLOSED, &con->state))
+               goto out_unlock;
+
+       con_close_socket(con);
+
+       if (con->in_msg) {
+               ceph_msg_put(con->in_msg);
+               con->in_msg = NULL;
+       }
+
+       /* Requeue anything that hasn't been acked */
+       list_splice_init(&con->out_sent, &con->out_queue);
+
+       /* If there are no messages in the queue, place the connection
+        * in a STANDBY state (i.e., don't try to reconnect just yet). */
+       if (list_empty(&con->out_queue) && !con->out_keepalive_pending) {
+               dout("fault setting STANDBY\n");
+               set_bit(STANDBY, &con->state);
+       } else {
+               /* retry after a delay. */
+               if (con->delay == 0)
+                       con->delay = BASE_DELAY_INTERVAL;
+               else if (con->delay < MAX_DELAY_INTERVAL)
+                       con->delay *= 2;
+               dout("fault queueing %p delay %lu\n", con, con->delay);
+               con->ops->get(con);
+               if (queue_delayed_work(ceph_msgr_wq, &con->work,
+                                      round_jiffies_relative(con->delay)) == 0)
+                       con->ops->put(con);
+       }
+
+out_unlock:
+       mutex_unlock(&con->mutex);
+out:
+       /*
+        * in case we faulted due to authentication, invalidate our
+        * current tickets so that we can get new ones.
+         */
+       if (con->auth_retry && con->ops->invalidate_authorizer) {
+               dout("calling invalidate_authorizer()\n");
+               con->ops->invalidate_authorizer(con);
+       }
+
+       if (con->ops->fault)
+               con->ops->fault(con);
+}
+
+
+
+/*
+ * create a new messenger instance
+ */
+struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
+{
+       struct ceph_messenger *msgr;
+
+       msgr = kzalloc(sizeof(*msgr), GFP_KERNEL);
+       if (msgr == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock_init(&msgr->global_seq_lock);
+
+       /* the zero page is needed if a request is "canceled" while the message
+        * is being written over the socket */
+       msgr->zero_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!msgr->zero_page) {
+               kfree(msgr);
+               return ERR_PTR(-ENOMEM);
+       }
+       kmap(msgr->zero_page);
+
+       if (myaddr)
+               msgr->inst.addr = *myaddr;
+
+       /* select a random nonce */
+       msgr->inst.addr.type = 0;
+       get_random_bytes(&msgr->inst.addr.nonce, sizeof(msgr->inst.addr.nonce));
+       encode_my_addr(msgr);
+
+       dout("messenger_create %p\n", msgr);
+       return msgr;
+}
+
+void ceph_messenger_destroy(struct ceph_messenger *msgr)
+{
+       dout("destroy %p\n", msgr);
+       kunmap(msgr->zero_page);
+       __free_page(msgr->zero_page);
+       kfree(msgr);
+       dout("destroyed messenger %p\n", msgr);
+}
+
+/*
+ * Queue up an outgoing message on the given connection.
+ */
+void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       if (test_bit(CLOSED, &con->state)) {
+               dout("con_send %p closed, dropping %p\n", con, msg);
+               ceph_msg_put(msg);
+               return;
+       }
+
+       /* set src+dst */
+       msg->hdr.src.name = con->msgr->inst.name;
+       msg->hdr.src.addr = con->msgr->my_enc_addr;
+       msg->hdr.orig_src = msg->hdr.src;
+
+       BUG_ON(msg->front.iov_len != le32_to_cpu(msg->hdr.front_len));
+
+       /* queue */
+       mutex_lock(&con->mutex);
+       BUG_ON(!list_empty(&msg->list_head));
+       list_add_tail(&msg->list_head, &con->out_queue);
+       dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg,
+            ENTITY_NAME(con->peer_name), le16_to_cpu(msg->hdr.type),
+            ceph_msg_type_name(le16_to_cpu(msg->hdr.type)),
+            le32_to_cpu(msg->hdr.front_len),
+            le32_to_cpu(msg->hdr.middle_len),
+            le32_to_cpu(msg->hdr.data_len));
+       mutex_unlock(&con->mutex);
+
+       /* if there wasn't anything waiting to send before, queue
+        * new work */
+       if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+               queue_con(con);
+}
+
+/*
+ * Revoke a message that was previously queued for send
+ */
+void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       mutex_lock(&con->mutex);
+       if (!list_empty(&msg->list_head)) {
+               dout("con_revoke %p msg %p\n", con, msg);
+               list_del_init(&msg->list_head);
+               ceph_msg_put(msg);
+               msg->hdr.seq = 0;
+               if (con->out_msg == msg) {
+                       ceph_msg_put(con->out_msg);
+                       con->out_msg = NULL;
+               }
+               if (con->out_kvec_is_msg) {
+                       con->out_skip = con->out_kvec_bytes;
+                       con->out_kvec_is_msg = false;
+               }
+       } else {
+               dout("con_revoke %p msg %p - not queued (sent?)\n", con, msg);
+       }
+       mutex_unlock(&con->mutex);
+}
+
+/*
+ * Revoke a message that we may be reading data into
+ */
+void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       mutex_lock(&con->mutex);
+       if (con->in_msg && con->in_msg == msg) {
+               unsigned front_len = le32_to_cpu(con->in_hdr.front_len);
+               unsigned middle_len = le32_to_cpu(con->in_hdr.middle_len);
+               unsigned data_len = le32_to_cpu(con->in_hdr.data_len);
+
+               /* skip rest of message */
+               dout("con_revoke_pages %p msg %p revoked\n", con, msg);
+                       con->in_base_pos = con->in_base_pos -
+                               sizeof(struct ceph_msg_header) -
+                               front_len -
+                               middle_len -
+                               data_len -
+                               sizeof(struct ceph_msg_footer);
+               ceph_msg_put(con->in_msg);
+               con->in_msg = NULL;
+               con->in_tag = CEPH_MSGR_TAG_READY;
+       } else {
+               dout("con_revoke_pages %p msg %p pages %p no-op\n",
+                    con, con->in_msg, msg);
+       }
+       mutex_unlock(&con->mutex);
+}
+
+/*
+ * Queue a keepalive byte to ensure the tcp connection is alive.
+ */
+void ceph_con_keepalive(struct ceph_connection *con)
+{
+       if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
+           test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+               queue_con(con);
+}
+
+
+/*
+ * construct a new message with given type, size
+ * the new msg has a ref count of 1.
+ */
+struct ceph_msg *ceph_msg_new(int type, int front_len,
+                             int page_len, int page_off, struct page **pages)
+{
+       struct ceph_msg *m;
+
+       m = kmalloc(sizeof(*m), GFP_NOFS);
+       if (m == NULL)
+               goto out;
+       kref_init(&m->kref);
+       INIT_LIST_HEAD(&m->list_head);
+
+       m->hdr.type = cpu_to_le16(type);
+       m->hdr.front_len = cpu_to_le32(front_len);
+       m->hdr.middle_len = 0;
+       m->hdr.data_len = cpu_to_le32(page_len);
+       m->hdr.data_off = cpu_to_le16(page_off);
+       m->hdr.priority = cpu_to_le16(CEPH_MSG_PRIO_DEFAULT);
+       m->footer.front_crc = 0;
+       m->footer.middle_crc = 0;
+       m->footer.data_crc = 0;
+       m->front_max = front_len;
+       m->front_is_vmalloc = false;
+       m->more_to_follow = false;
+       m->pool = NULL;
+
+       /* front */
+       if (front_len) {
+               if (front_len > PAGE_CACHE_SIZE) {
+                       m->front.iov_base = __vmalloc(front_len, GFP_NOFS,
+                                                     PAGE_KERNEL);
+                       m->front_is_vmalloc = true;
+               } else {
+                       m->front.iov_base = kmalloc(front_len, GFP_NOFS);
+               }
+               if (m->front.iov_base == NULL) {
+                       pr_err("msg_new can't allocate %d bytes\n",
+                            front_len);
+                       goto out2;
+               }
+       } else {
+               m->front.iov_base = NULL;
+       }
+       m->front.iov_len = front_len;
+
+       /* middle */
+       m->middle = NULL;
+
+       /* data */
+       m->nr_pages = calc_pages_for(page_off, page_len);
+       m->pages = pages;
+       m->pagelist = NULL;
+
+       dout("ceph_msg_new %p page %d~%d -> %d\n", m, page_off, page_len,
+            m->nr_pages);
+       return m;
+
+out2:
+       ceph_msg_put(m);
+out:
+       pr_err("msg_new can't create type %d len %d\n", type, front_len);
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * Allocate "middle" portion of a message, if it is needed and wasn't
+ * allocated by alloc_msg.  This allows us to read a small fixed-size
+ * per-type header in the front and then gracefully fail (i.e.,
+ * propagate the error to the caller based on info in the front) when
+ * the middle is too large.
+ */
+static int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       int type = le16_to_cpu(msg->hdr.type);
+       int middle_len = le32_to_cpu(msg->hdr.middle_len);
+
+       dout("alloc_middle %p type %d %s middle_len %d\n", msg, type,
+            ceph_msg_type_name(type), middle_len);
+       BUG_ON(!middle_len);
+       BUG_ON(msg->middle);
+
+       msg->middle = ceph_buffer_new(middle_len, GFP_NOFS);
+       if (!msg->middle)
+               return -ENOMEM;
+       return 0;
+}
+
+/*
+ * Generic message allocator, for incoming messages.
+ */
+static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
+                               struct ceph_msg_header *hdr,
+                               int *skip)
+{
+       int type = le16_to_cpu(hdr->type);
+       int front_len = le32_to_cpu(hdr->front_len);
+       int middle_len = le32_to_cpu(hdr->middle_len);
+       struct ceph_msg *msg = NULL;
+       int ret;
+
+       if (con->ops->alloc_msg) {
+               mutex_unlock(&con->mutex);
+               msg = con->ops->alloc_msg(con, hdr, skip);
+               mutex_lock(&con->mutex);
+               if (IS_ERR(msg))
+                       return msg;
+
+               if (*skip)
+                       return NULL;
+       }
+       if (!msg) {
+               *skip = 0;
+               msg = ceph_msg_new(type, front_len, 0, 0, NULL);
+               if (!msg) {
+                       pr_err("unable to allocate msg type %d len %d\n",
+                              type, front_len);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
+       memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
+
+       if (middle_len) {
+               ret = ceph_alloc_middle(con, msg);
+
+               if (ret < 0) {
+                       ceph_msg_put(msg);
+                       return msg;
+               }
+       }
+
+       return msg;
+}
+
+
+/*
+ * Free a generically kmalloc'd message.
+ */
+void ceph_msg_kfree(struct ceph_msg *m)
+{
+       dout("msg_kfree %p\n", m);
+       if (m->front_is_vmalloc)
+               vfree(m->front.iov_base);
+       else
+               kfree(m->front.iov_base);
+       kfree(m);
+}
+
+/*
+ * Drop a msg ref.  Destroy as needed.
+ */
+void ceph_msg_last_put(struct kref *kref)
+{
+       struct ceph_msg *m = container_of(kref, struct ceph_msg, kref);
+
+       dout("ceph_msg_put last one on %p\n", m);
+       WARN_ON(!list_empty(&m->list_head));
+
+       /* drop middle, data, if any */
+       if (m->middle) {
+               ceph_buffer_put(m->middle);
+               m->middle = NULL;
+       }
+       m->nr_pages = 0;
+       m->pages = NULL;
+
+       if (m->pagelist) {
+               ceph_pagelist_release(m->pagelist);
+               kfree(m->pagelist);
+               m->pagelist = NULL;
+       }
+
+       if (m->pool)
+               ceph_msgpool_put(m->pool, m);
+       else
+               ceph_msg_kfree(m);
+}
+
+void ceph_msg_dump(struct ceph_msg *msg)
+{
+       pr_debug("msg_dump %p (front_max %d nr_pages %d)\n", msg,
+                msg->front_max, msg->nr_pages);
+       print_hex_dump(KERN_DEBUG, "header: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      &msg->hdr, sizeof(msg->hdr), true);
+       print_hex_dump(KERN_DEBUG, " front: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      msg->front.iov_base, msg->front.iov_len, true);
+       if (msg->middle)
+               print_hex_dump(KERN_DEBUG, "middle: ",
+                              DUMP_PREFIX_OFFSET, 16, 1,
+                              msg->middle->vec.iov_base,
+                              msg->middle->vec.iov_len, true);
+       print_hex_dump(KERN_DEBUG, "footer: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      &msg->footer, sizeof(msg->footer), true);
+}
diff --git a/fs/ceph/messenger.h b/fs/ceph/messenger.h
new file mode 100644 (file)
index 0000000..4caaa59
--- /dev/null
@@ -0,0 +1,254 @@
+#ifndef __FS_CEPH_MESSENGER_H
+#define __FS_CEPH_MESSENGER_H
+
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/net.h>
+#include <linux/radix-tree.h>
+#include <linux/uio.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include "types.h"
+#include "buffer.h"
+
+struct ceph_msg;
+struct ceph_connection;
+
+extern struct workqueue_struct *ceph_msgr_wq;       /* receive work queue */
+
+/*
+ * Ceph defines these callbacks for handling connection events.
+ */
+struct ceph_connection_operations {
+       struct ceph_connection *(*get)(struct ceph_connection *);
+       void (*put)(struct ceph_connection *);
+
+       /* handle an incoming message. */
+       void (*dispatch) (struct ceph_connection *con, struct ceph_msg *m);
+
+       /* authorize an outgoing connection */
+       int (*get_authorizer) (struct ceph_connection *con,
+                              void **buf, int *len, int *proto,
+                              void **reply_buf, int *reply_len, int force_new);
+       int (*verify_authorizer_reply) (struct ceph_connection *con, int len);
+       int (*invalidate_authorizer)(struct ceph_connection *con);
+
+       /* protocol version mismatch */
+       void (*bad_proto) (struct ceph_connection *con);
+
+       /* there was some error on the socket (disconnect, whatever) */
+       void (*fault) (struct ceph_connection *con);
+
+       /* a remote host as terminated a message exchange session, and messages
+        * we sent (or they tried to send us) may be lost. */
+       void (*peer_reset) (struct ceph_connection *con);
+
+       struct ceph_msg * (*alloc_msg) (struct ceph_connection *con,
+                                       struct ceph_msg_header *hdr,
+                                       int *skip);
+};
+
+extern const char *ceph_name_type_str(int t);
+
+/* use format string %s%d */
+#define ENTITY_NAME(n) ceph_name_type_str((n).type), le64_to_cpu((n).num)
+
+struct ceph_messenger {
+       struct ceph_entity_inst inst;    /* my name+address */
+       struct ceph_entity_addr my_enc_addr;
+       struct page *zero_page;          /* used in certain error cases */
+
+       bool nocrc;
+
+       /*
+        * the global_seq counts connections i (attempt to) initiate
+        * in order to disambiguate certain connect race conditions.
+        */
+       u32 global_seq;
+       spinlock_t global_seq_lock;
+};
+
+/*
+ * a single message.  it contains a header (src, dest, message type, etc.),
+ * footer (crc values, mainly), a "front" message body, and possibly a
+ * data payload (stored in some number of pages).
+ */
+struct ceph_msg {
+       struct ceph_msg_header hdr;     /* header */
+       struct ceph_msg_footer footer;  /* footer */
+       struct kvec front;              /* unaligned blobs of message */
+       struct ceph_buffer *middle;
+       struct page **pages;            /* data payload.  NOT OWNER. */
+       unsigned nr_pages;              /* size of page array */
+       struct ceph_pagelist *pagelist; /* instead of pages */
+       struct list_head list_head;
+       struct kref kref;
+       bool front_is_vmalloc;
+       bool more_to_follow;
+       int front_max;
+
+       struct ceph_msgpool *pool;
+};
+
+struct ceph_msg_pos {
+       int page, page_pos;  /* which page; offset in page */
+       int data_pos;        /* offset in data payload */
+       int did_page_crc;    /* true if we've calculated crc for current page */
+};
+
+/* ceph connection fault delay defaults, for exponential backoff */
+#define BASE_DELAY_INTERVAL    (HZ/2)
+#define MAX_DELAY_INTERVAL     (5 * 60 * HZ)
+
+/*
+ * ceph_connection state bit flags
+ *
+ * QUEUED and BUSY are used together to ensure that only a single
+ * thread is currently opening, reading or writing data to the socket.
+ */
+#define LOSSYTX         0  /* we can close channel or drop messages on errors */
+#define CONNECTING     1
+#define NEGOTIATING    2
+#define KEEPALIVE_PENDING      3
+#define WRITE_PENDING  4  /* we have data ready to send */
+#define QUEUED          5  /* there is work queued on this connection */
+#define BUSY            6  /* work is being done */
+#define STANDBY                8  /* no outgoing messages, socket closed.  we keep
+                           * the ceph_connection around to maintain shared
+                           * state with the peer. */
+#define CLOSED         10 /* we've closed the connection */
+#define SOCK_CLOSED    11 /* socket state changed to closed */
+#define OPENING         13 /* open connection w/ (possibly new) peer */
+#define DEAD            14 /* dead, about to kfree */
+
+/*
+ * A single connection with another host.
+ *
+ * We maintain a queue of outgoing messages, and some session state to
+ * ensure that we can preserve the lossless, ordered delivery of
+ * messages in the case of a TCP disconnect.
+ */
+struct ceph_connection {
+       void *private;
+       atomic_t nref;
+
+       const struct ceph_connection_operations *ops;
+
+       struct ceph_messenger *msgr;
+       struct socket *sock;
+       unsigned long state;    /* connection state (see flags above) */
+       const char *error_msg;  /* error message, if any */
+
+       struct ceph_entity_addr peer_addr; /* peer address */
+       struct ceph_entity_name peer_name; /* peer name */
+       struct ceph_entity_addr peer_addr_for_me;
+       u32 connect_seq;      /* identify the most recent connection
+                                attempt for this connection, client */
+       u32 peer_global_seq;  /* peer's global seq for this connection */
+
+       int auth_retry;       /* true if we need a newer authorizer */
+       void *auth_reply_buf;   /* where to put the authorizer reply */
+       int auth_reply_buf_len;
+
+       struct mutex mutex;
+
+       /* out queue */
+       struct list_head out_queue;
+       struct list_head out_sent;   /* sending or sent but unacked */
+       u64 out_seq;                 /* last message queued for send */
+       u64 out_seq_sent;            /* last message sent */
+       bool out_keepalive_pending;
+
+       u64 in_seq, in_seq_acked;  /* last message received, acked */
+
+       /* connection negotiation temps */
+       char in_banner[CEPH_BANNER_MAX_LEN];
+       union {
+               struct {  /* outgoing connection */
+                       struct ceph_msg_connect out_connect;
+                       struct ceph_msg_connect_reply in_reply;
+               };
+               struct {  /* incoming */
+                       struct ceph_msg_connect in_connect;
+                       struct ceph_msg_connect_reply out_reply;
+               };
+       };
+       struct ceph_entity_addr actual_peer_addr;
+
+       /* message out temps */
+       struct ceph_msg *out_msg;        /* sending message (== tail of
+                                           out_sent) */
+       bool out_msg_done;
+       struct ceph_msg_pos out_msg_pos;
+
+       struct kvec out_kvec[8],         /* sending header/footer data */
+               *out_kvec_cur;
+       int out_kvec_left;   /* kvec's left in out_kvec */
+       int out_skip;        /* skip this many bytes */
+       int out_kvec_bytes;  /* total bytes left */
+       bool out_kvec_is_msg; /* kvec refers to out_msg */
+       int out_more;        /* there is more data after the kvecs */
+       __le64 out_temp_ack; /* for writing an ack */
+
+       /* message in temps */
+       struct ceph_msg_header in_hdr;
+       struct ceph_msg *in_msg;
+       struct ceph_msg_pos in_msg_pos;
+       u32 in_front_crc, in_middle_crc, in_data_crc;  /* calculated crc */
+
+       char in_tag;         /* protocol control byte */
+       int in_base_pos;     /* bytes read */
+       __le64 in_temp_ack;  /* for reading an ack */
+
+       struct delayed_work work;           /* send|recv work */
+       unsigned long       delay;          /* current delay interval */
+};
+
+
+extern const char *pr_addr(const struct sockaddr_storage *ss);
+extern int ceph_parse_ips(const char *c, const char *end,
+                         struct ceph_entity_addr *addr,
+                         int max_count, int *count);
+
+
+extern int ceph_msgr_init(void);
+extern void ceph_msgr_exit(void);
+
+extern struct ceph_messenger *ceph_messenger_create(
+       struct ceph_entity_addr *myaddr);
+extern void ceph_messenger_destroy(struct ceph_messenger *);
+
+extern void ceph_con_init(struct ceph_messenger *msgr,
+                         struct ceph_connection *con);
+extern void ceph_con_open(struct ceph_connection *con,
+                         struct ceph_entity_addr *addr);
+extern void ceph_con_close(struct ceph_connection *con);
+extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg);
+extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg);
+extern void ceph_con_revoke_message(struct ceph_connection *con,
+                                 struct ceph_msg *msg);
+extern void ceph_con_keepalive(struct ceph_connection *con);
+extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
+extern void ceph_con_put(struct ceph_connection *con);
+
+extern struct ceph_msg *ceph_msg_new(int type, int front_len,
+                                    int page_len, int page_off,
+                                    struct page **pages);
+extern void ceph_msg_kfree(struct ceph_msg *m);
+
+
+static inline struct ceph_msg *ceph_msg_get(struct ceph_msg *msg)
+{
+       kref_get(&msg->kref);
+       return msg;
+}
+extern void ceph_msg_last_put(struct kref *kref);
+static inline void ceph_msg_put(struct ceph_msg *msg)
+{
+       kref_put(&msg->kref, ceph_msg_last_put);
+}
+
+extern void ceph_msg_dump(struct ceph_msg *msg);
+
+#endif
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c
new file mode 100644 (file)
index 0000000..890597c
--- /dev/null
@@ -0,0 +1,834 @@
+#include "ceph_debug.h"
+
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+#include "mon_client.h"
+#include "super.h"
+#include "auth.h"
+#include "decode.h"
+
+/*
+ * Interact with Ceph monitor cluster.  Handle requests for new map
+ * versions, and periodically resend as needed.  Also implement
+ * statfs() and umount().
+ *
+ * A small cluster of Ceph "monitors" are responsible for managing critical
+ * cluster configuration and state information.  An odd number (e.g., 3, 5)
+ * of cmon daemons use a modified version of the Paxos part-time parliament
+ * algorithm to manage the MDS map (mds cluster membership), OSD map, and
+ * list of clients who have mounted the file system.
+ *
+ * We maintain an open, active session with a monitor at all times in order to
+ * receive timely MDSMap updates.  We periodically send a keepalive byte on the
+ * TCP socket to ensure we detect a failure.  If the connection does break, we
+ * randomly hunt for a new monitor.  Once the connection is reestablished, we
+ * resend any outstanding requests.
+ */
+
+const static struct ceph_connection_operations mon_con_ops;
+
+static int __validate_auth(struct ceph_mon_client *monc);
+
+/*
+ * Decode a monmap blob (e.g., during mount).
+ */
+struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
+{
+       struct ceph_monmap *m = NULL;
+       int i, err = -EINVAL;
+       struct ceph_fsid fsid;
+       u32 epoch, num_mon;
+       u16 version;
+       u32 len;
+
+       ceph_decode_32_safe(&p, end, len, bad);
+       ceph_decode_need(&p, end, len, bad);
+
+       dout("monmap_decode %p %p len %d\n", p, end, (int)(end-p));
+
+       ceph_decode_16_safe(&p, end, version, bad);
+
+       ceph_decode_need(&p, end, sizeof(fsid) + 2*sizeof(u32), bad);
+       ceph_decode_copy(&p, &fsid, sizeof(fsid));
+       epoch = ceph_decode_32(&p);
+
+       num_mon = ceph_decode_32(&p);
+       ceph_decode_need(&p, end, num_mon*sizeof(m->mon_inst[0]), bad);
+
+       if (num_mon >= CEPH_MAX_MON)
+               goto bad;
+       m = kmalloc(sizeof(*m) + sizeof(m->mon_inst[0])*num_mon, GFP_NOFS);
+       if (m == NULL)
+               return ERR_PTR(-ENOMEM);
+       m->fsid = fsid;
+       m->epoch = epoch;
+       m->num_mon = num_mon;
+       ceph_decode_copy(&p, m->mon_inst, num_mon*sizeof(m->mon_inst[0]));
+       for (i = 0; i < num_mon; i++)
+               ceph_decode_addr(&m->mon_inst[i].addr);
+
+       dout("monmap_decode epoch %d, num_mon %d\n", m->epoch,
+            m->num_mon);
+       for (i = 0; i < m->num_mon; i++)
+               dout("monmap_decode  mon%d is %s\n", i,
+                    pr_addr(&m->mon_inst[i].addr.in_addr));
+       return m;
+
+bad:
+       dout("monmap_decode failed with %d\n", err);
+       kfree(m);
+       return ERR_PTR(err);
+}
+
+/*
+ * return true if *addr is included in the monmap.
+ */
+int ceph_monmap_contains(struct ceph_monmap *m, struct ceph_entity_addr *addr)
+{
+       int i;
+
+       for (i = 0; i < m->num_mon; i++)
+               if (memcmp(addr, &m->mon_inst[i].addr, sizeof(*addr)) == 0)
+                       return 1;
+       return 0;
+}
+
+/*
+ * Send an auth request.
+ */
+static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
+{
+       monc->pending_auth = 1;
+       monc->m_auth->front.iov_len = len;
+       monc->m_auth->hdr.front_len = cpu_to_le32(len);
+       ceph_msg_get(monc->m_auth);  /* keep our ref */
+       ceph_con_send(monc->con, monc->m_auth);
+}
+
+/*
+ * Close monitor session, if any.
+ */
+static void __close_session(struct ceph_mon_client *monc)
+{
+       if (monc->con) {
+               dout("__close_session closing mon%d\n", monc->cur_mon);
+               ceph_con_revoke(monc->con, monc->m_auth);
+               ceph_con_close(monc->con);
+               monc->cur_mon = -1;
+               monc->pending_auth = 0;
+               ceph_auth_reset(monc->auth);
+       }
+}
+
+/*
+ * Open a session with a (new) monitor.
+ */
+static int __open_session(struct ceph_mon_client *monc)
+{
+       char r;
+       int ret;
+
+       if (monc->cur_mon < 0) {
+               get_random_bytes(&r, 1);
+               monc->cur_mon = r % monc->monmap->num_mon;
+               dout("open_session num=%d r=%d -> mon%d\n",
+                    monc->monmap->num_mon, r, monc->cur_mon);
+               monc->sub_sent = 0;
+               monc->sub_renew_after = jiffies;  /* i.e., expired */
+               monc->want_next_osdmap = !!monc->want_next_osdmap;
+
+               dout("open_session mon%d opening\n", monc->cur_mon);
+               monc->con->peer_name.type = CEPH_ENTITY_TYPE_MON;
+               monc->con->peer_name.num = cpu_to_le64(monc->cur_mon);
+               ceph_con_open(monc->con,
+                             &monc->monmap->mon_inst[monc->cur_mon].addr);
+
+               /* initiatiate authentication handshake */
+               ret = ceph_auth_build_hello(monc->auth,
+                                           monc->m_auth->front.iov_base,
+                                           monc->m_auth->front_max);
+               __send_prepared_auth_request(monc, ret);
+       } else {
+               dout("open_session mon%d already open\n", monc->cur_mon);
+       }
+       return 0;
+}
+
+static bool __sub_expired(struct ceph_mon_client *monc)
+{
+       return time_after_eq(jiffies, monc->sub_renew_after);
+}
+
+/*
+ * Reschedule delayed work timer.
+ */
+static void __schedule_delayed(struct ceph_mon_client *monc)
+{
+       unsigned delay;
+
+       if (monc->cur_mon < 0 || __sub_expired(monc))
+               delay = 10 * HZ;
+       else
+               delay = 20 * HZ;
+       dout("__schedule_delayed after %u\n", delay);
+       schedule_delayed_work(&monc->delayed_work, delay);
+}
+
+/*
+ * Send subscribe request for mdsmap and/or osdmap.
+ */
+static void __send_subscribe(struct ceph_mon_client *monc)
+{
+       dout("__send_subscribe sub_sent=%u exp=%u want_osd=%d\n",
+            (unsigned)monc->sub_sent, __sub_expired(monc),
+            monc->want_next_osdmap);
+       if ((__sub_expired(monc) && !monc->sub_sent) ||
+           monc->want_next_osdmap == 1) {
+               struct ceph_msg *msg;
+               struct ceph_mon_subscribe_item *i;
+               void *p, *end;
+
+               msg = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE, 96, 0, 0, NULL);
+               if (!msg)
+                       return;
+
+               p = msg->front.iov_base;
+               end = p + msg->front.iov_len;
+
+               dout("__send_subscribe to 'mdsmap' %u+\n",
+                    (unsigned)monc->have_mdsmap);
+               if (monc->want_next_osdmap) {
+                       dout("__send_subscribe to 'osdmap' %u\n",
+                            (unsigned)monc->have_osdmap);
+                       ceph_encode_32(&p, 3);
+                       ceph_encode_string(&p, end, "osdmap", 6);
+                       i = p;
+                       i->have = cpu_to_le64(monc->have_osdmap);
+                       i->onetime = 1;
+                       p += sizeof(*i);
+                       monc->want_next_osdmap = 2;  /* requested */
+               } else {
+                       ceph_encode_32(&p, 2);
+               }
+               ceph_encode_string(&p, end, "mdsmap", 6);
+               i = p;
+               i->have = cpu_to_le64(monc->have_mdsmap);
+               i->onetime = 0;
+               p += sizeof(*i);
+               ceph_encode_string(&p, end, "monmap", 6);
+               i = p;
+               i->have = 0;
+               i->onetime = 0;
+               p += sizeof(*i);
+
+               msg->front.iov_len = p - msg->front.iov_base;
+               msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+               ceph_con_send(monc->con, msg);
+
+               monc->sub_sent = jiffies | 1;  /* never 0 */
+       }
+}
+
+static void handle_subscribe_ack(struct ceph_mon_client *monc,
+                                struct ceph_msg *msg)
+{
+       unsigned seconds;
+       struct ceph_mon_subscribe_ack *h = msg->front.iov_base;
+
+       if (msg->front.iov_len < sizeof(*h))
+               goto bad;
+       seconds = le32_to_cpu(h->duration);
+
+       mutex_lock(&monc->mutex);
+       if (monc->hunting) {
+               pr_info("mon%d %s session established\n",
+                       monc->cur_mon, pr_addr(&monc->con->peer_addr.in_addr));
+               monc->hunting = false;
+       }
+       dout("handle_subscribe_ack after %d seconds\n", seconds);
+       monc->sub_renew_after = monc->sub_sent + (seconds >> 1)*HZ - 1;
+       monc->sub_sent = 0;
+       mutex_unlock(&monc->mutex);
+       return;
+bad:
+       pr_err("got corrupt subscribe-ack msg\n");
+       ceph_msg_dump(msg);
+}
+
+/*
+ * Keep track of which maps we have
+ */
+int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 got)
+{
+       mutex_lock(&monc->mutex);
+       monc->have_mdsmap = got;
+       mutex_unlock(&monc->mutex);
+       return 0;
+}
+
+int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 got)
+{
+       mutex_lock(&monc->mutex);
+       monc->have_osdmap = got;
+       monc->want_next_osdmap = 0;
+       mutex_unlock(&monc->mutex);
+       return 0;
+}
+
+/*
+ * Register interest in the next osdmap
+ */
+void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc)
+{
+       dout("request_next_osdmap have %u\n", monc->have_osdmap);
+       mutex_lock(&monc->mutex);
+       if (!monc->want_next_osdmap)
+               monc->want_next_osdmap = 1;
+       if (monc->want_next_osdmap < 2)
+               __send_subscribe(monc);
+       mutex_unlock(&monc->mutex);
+}
+
+/*
+ *
+ */
+int ceph_monc_open_session(struct ceph_mon_client *monc)
+{
+       if (!monc->con) {
+               monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL);
+               if (!monc->con)
+                       return -ENOMEM;
+               ceph_con_init(monc->client->msgr, monc->con);
+               monc->con->private = monc;
+               monc->con->ops = &mon_con_ops;
+       }
+
+       mutex_lock(&monc->mutex);
+       __open_session(monc);
+       __schedule_delayed(monc);
+       mutex_unlock(&monc->mutex);
+       return 0;
+}
+
+/*
+ * The monitor responds with mount ack indicate mount success.  The
+ * included client ticket allows the client to talk to MDSs and OSDs.
+ */
+static void ceph_monc_handle_map(struct ceph_mon_client *monc,
+                                struct ceph_msg *msg)
+{
+       struct ceph_client *client = monc->client;
+       struct ceph_monmap *monmap = NULL, *old = monc->monmap;
+       void *p, *end;
+
+       mutex_lock(&monc->mutex);
+
+       dout("handle_monmap\n");
+       p = msg->front.iov_base;
+       end = p + msg->front.iov_len;
+
+       monmap = ceph_monmap_decode(p, end);
+       if (IS_ERR(monmap)) {
+               pr_err("problem decoding monmap, %d\n",
+                      (int)PTR_ERR(monmap));
+               goto out;
+       }
+
+       if (ceph_check_fsid(monc->client, &monmap->fsid) < 0) {
+               kfree(monmap);
+               goto out;
+       }
+
+       client->monc.monmap = monmap;
+       kfree(old);
+
+out:
+       mutex_unlock(&monc->mutex);
+       wake_up(&client->auth_wq);
+}
+
+/*
+ * statfs
+ */
+static struct ceph_mon_statfs_request *__lookup_statfs(
+       struct ceph_mon_client *monc, u64 tid)
+{
+       struct ceph_mon_statfs_request *req;
+       struct rb_node *n = monc->statfs_request_tree.rb_node;
+
+       while (n) {
+               req = rb_entry(n, struct ceph_mon_statfs_request, node);
+               if (tid < req->tid)
+                       n = n->rb_left;
+               else if (tid > req->tid)
+                       n = n->rb_right;
+               else
+                       return req;
+       }
+       return NULL;
+}
+
+static void __insert_statfs(struct ceph_mon_client *monc,
+                           struct ceph_mon_statfs_request *new)
+{
+       struct rb_node **p = &monc->statfs_request_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_mon_statfs_request *req = NULL;
+
+       while (*p) {
+               parent = *p;
+               req = rb_entry(parent, struct ceph_mon_statfs_request, node);
+               if (new->tid < req->tid)
+                       p = &(*p)->rb_left;
+               else if (new->tid > req->tid)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->node, parent, p);
+       rb_insert_color(&new->node, &monc->statfs_request_tree);
+}
+
+static void handle_statfs_reply(struct ceph_mon_client *monc,
+                               struct ceph_msg *msg)
+{
+       struct ceph_mon_statfs_request *req;
+       struct ceph_mon_statfs_reply *reply = msg->front.iov_base;
+       u64 tid;
+
+       if (msg->front.iov_len != sizeof(*reply))
+               goto bad;
+       tid = le64_to_cpu(msg->hdr.tid);
+       dout("handle_statfs_reply %p tid %llu\n", msg, tid);
+
+       mutex_lock(&monc->mutex);
+       req = __lookup_statfs(monc, tid);
+       if (req) {
+               *req->buf = reply->st;
+               req->result = 0;
+       }
+       mutex_unlock(&monc->mutex);
+       if (req)
+               complete(&req->completion);
+       return;
+
+bad:
+       pr_err("corrupt statfs reply, no tid\n");
+       ceph_msg_dump(msg);
+}
+
+/*
+ * (re)send a statfs request
+ */
+static int send_statfs(struct ceph_mon_client *monc,
+                      struct ceph_mon_statfs_request *req)
+{
+       struct ceph_msg *msg;
+       struct ceph_mon_statfs *h;
+
+       dout("send_statfs tid %llu\n", req->tid);
+       msg = ceph_msg_new(CEPH_MSG_STATFS, sizeof(*h), 0, 0, NULL);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+       req->request = msg;
+       msg->hdr.tid = cpu_to_le64(req->tid);
+       h = msg->front.iov_base;
+       h->monhdr.have_version = 0;
+       h->monhdr.session_mon = cpu_to_le16(-1);
+       h->monhdr.session_mon_tid = 0;
+       h->fsid = monc->monmap->fsid;
+       ceph_con_send(monc->con, msg);
+       return 0;
+}
+
+/*
+ * Do a synchronous statfs().
+ */
+int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf)
+{
+       struct ceph_mon_statfs_request req;
+       int err;
+
+       req.buf = buf;
+       init_completion(&req.completion);
+
+       /* allocate memory for reply */
+       err = ceph_msgpool_resv(&monc->msgpool_statfs_reply, 1);
+       if (err)
+               return err;
+
+       /* register request */
+       mutex_lock(&monc->mutex);
+       req.tid = ++monc->last_tid;
+       req.last_attempt = jiffies;
+       req.delay = BASE_DELAY_INTERVAL;
+       __insert_statfs(monc, &req);
+       monc->num_statfs_requests++;
+       mutex_unlock(&monc->mutex);
+
+       /* send request and wait */
+       err = send_statfs(monc, &req);
+       if (!err)
+               err = wait_for_completion_interruptible(&req.completion);
+
+       mutex_lock(&monc->mutex);
+       rb_erase(&req.node, &monc->statfs_request_tree);
+       monc->num_statfs_requests--;
+       ceph_msgpool_resv(&monc->msgpool_statfs_reply, -1);
+       mutex_unlock(&monc->mutex);
+
+       if (!err)
+               err = req.result;
+       return err;
+}
+
+/*
+ * Resend pending statfs requests.
+ */
+static void __resend_statfs(struct ceph_mon_client *monc)
+{
+       struct ceph_mon_statfs_request *req;
+       struct rb_node *p;
+
+       for (p = rb_first(&monc->statfs_request_tree); p; p = rb_next(p)) {
+               req = rb_entry(p, struct ceph_mon_statfs_request, node);
+               send_statfs(monc, req);
+       }
+}
+
+/*
+ * Delayed work.  If we haven't mounted yet, retry.  Otherwise,
+ * renew/retry subscription as needed (in case it is timing out, or we
+ * got an ENOMEM).  And keep the monitor connection alive.
+ */
+static void delayed_work(struct work_struct *work)
+{
+       struct ceph_mon_client *monc =
+               container_of(work, struct ceph_mon_client, delayed_work.work);
+
+       dout("monc delayed_work\n");
+       mutex_lock(&monc->mutex);
+       if (monc->hunting) {
+               __close_session(monc);
+               __open_session(monc);  /* continue hunting */
+       } else {
+               ceph_con_keepalive(monc->con);
+
+               __validate_auth(monc);
+
+               if (monc->auth->ops->is_authenticated(monc->auth))
+                       __send_subscribe(monc);
+       }
+       __schedule_delayed(monc);
+       mutex_unlock(&monc->mutex);
+}
+
+/*
+ * On startup, we build a temporary monmap populated with the IPs
+ * provided by mount(2).
+ */
+static int build_initial_monmap(struct ceph_mon_client *monc)
+{
+       struct ceph_mount_args *args = monc->client->mount_args;
+       struct ceph_entity_addr *mon_addr = args->mon_addr;
+       int num_mon = args->num_mon;
+       int i;
+
+       /* build initial monmap */
+       monc->monmap = kzalloc(sizeof(*monc->monmap) +
+                              num_mon*sizeof(monc->monmap->mon_inst[0]),
+                              GFP_KERNEL);
+       if (!monc->monmap)
+               return -ENOMEM;
+       for (i = 0; i < num_mon; i++) {
+               monc->monmap->mon_inst[i].addr = mon_addr[i];
+               monc->monmap->mon_inst[i].addr.nonce = 0;
+               monc->monmap->mon_inst[i].name.type =
+                       CEPH_ENTITY_TYPE_MON;
+               monc->monmap->mon_inst[i].name.num = cpu_to_le64(i);
+       }
+       monc->monmap->num_mon = num_mon;
+       monc->have_fsid = false;
+
+       /* release addr memory */
+       kfree(args->mon_addr);
+       args->mon_addr = NULL;
+       args->num_mon = 0;
+       return 0;
+}
+
+int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
+{
+       int err = 0;
+
+       dout("init\n");
+       memset(monc, 0, sizeof(*monc));
+       monc->client = cl;
+       monc->monmap = NULL;
+       mutex_init(&monc->mutex);
+
+       err = build_initial_monmap(monc);
+       if (err)
+               goto out;
+
+       monc->con = NULL;
+
+       /* authentication */
+       monc->auth = ceph_auth_init(cl->mount_args->name,
+                                   cl->mount_args->secret);
+       if (IS_ERR(monc->auth))
+               return PTR_ERR(monc->auth);
+       monc->auth->want_keys =
+               CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON |
+               CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MDS;
+
+       /* msg pools */
+       err = ceph_msgpool_init(&monc->msgpool_subscribe_ack,
+                              sizeof(struct ceph_mon_subscribe_ack), 1, false);
+       if (err < 0)
+               goto out_monmap;
+       err = ceph_msgpool_init(&monc->msgpool_statfs_reply,
+                               sizeof(struct ceph_mon_statfs_reply), 0, false);
+       if (err < 0)
+               goto out_pool1;
+       err = ceph_msgpool_init(&monc->msgpool_auth_reply, 4096, 1, false);
+       if (err < 0)
+               goto out_pool2;
+
+       monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, 0, 0, NULL);
+       monc->pending_auth = 0;
+       if (IS_ERR(monc->m_auth)) {
+               err = PTR_ERR(monc->m_auth);
+               monc->m_auth = NULL;
+               goto out_pool3;
+       }
+
+       monc->cur_mon = -1;
+       monc->hunting = true;
+       monc->sub_renew_after = jiffies;
+       monc->sub_sent = 0;
+
+       INIT_DELAYED_WORK(&monc->delayed_work, delayed_work);
+       monc->statfs_request_tree = RB_ROOT;
+       monc->num_statfs_requests = 0;
+       monc->last_tid = 0;
+
+       monc->have_mdsmap = 0;
+       monc->have_osdmap = 0;
+       monc->want_next_osdmap = 1;
+       return 0;
+
+out_pool3:
+       ceph_msgpool_destroy(&monc->msgpool_auth_reply);
+out_pool2:
+       ceph_msgpool_destroy(&monc->msgpool_subscribe_ack);
+out_pool1:
+       ceph_msgpool_destroy(&monc->msgpool_statfs_reply);
+out_monmap:
+       kfree(monc->monmap);
+out:
+       return err;
+}
+
+void ceph_monc_stop(struct ceph_mon_client *monc)
+{
+       dout("stop\n");
+       cancel_delayed_work_sync(&monc->delayed_work);
+
+       mutex_lock(&monc->mutex);
+       __close_session(monc);
+       if (monc->con) {
+               monc->con->private = NULL;
+               monc->con->ops->put(monc->con);
+               monc->con = NULL;
+       }
+       mutex_unlock(&monc->mutex);
+
+       ceph_auth_destroy(monc->auth);
+
+       ceph_msg_put(monc->m_auth);
+       ceph_msgpool_destroy(&monc->msgpool_subscribe_ack);
+       ceph_msgpool_destroy(&monc->msgpool_statfs_reply);
+       ceph_msgpool_destroy(&monc->msgpool_auth_reply);
+
+       kfree(monc->monmap);
+}
+
+static void handle_auth_reply(struct ceph_mon_client *monc,
+                             struct ceph_msg *msg)
+{
+       int ret;
+
+       mutex_lock(&monc->mutex);
+       monc->pending_auth = 0;
+       ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
+                                    msg->front.iov_len,
+                                    monc->m_auth->front.iov_base,
+                                    monc->m_auth->front_max);
+       if (ret < 0) {
+               monc->client->auth_err = ret;
+               wake_up(&monc->client->auth_wq);
+       } else if (ret > 0) {
+               __send_prepared_auth_request(monc, ret);
+       } else if (monc->auth->ops->is_authenticated(monc->auth)) {
+               dout("authenticated, starting session\n");
+
+               monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
+               monc->client->msgr->inst.name.num = monc->auth->global_id;
+
+               __send_subscribe(monc);
+               __resend_statfs(monc);
+       }
+       mutex_unlock(&monc->mutex);
+}
+
+static int __validate_auth(struct ceph_mon_client *monc)
+{
+       int ret;
+
+       if (monc->pending_auth)
+               return 0;
+
+       ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base,
+                             monc->m_auth->front_max);
+       if (ret <= 0)
+               return ret; /* either an error, or no need to authenticate */
+       __send_prepared_auth_request(monc, ret);
+       return 0;
+}
+
+int ceph_monc_validate_auth(struct ceph_mon_client *monc)
+{
+       int ret;
+
+       mutex_lock(&monc->mutex);
+       ret = __validate_auth(monc);
+       mutex_unlock(&monc->mutex);
+       return ret;
+}
+
+/*
+ * handle incoming message
+ */
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_mon_client *monc = con->private;
+       int type = le16_to_cpu(msg->hdr.type);
+
+       if (!monc)
+               return;
+
+       switch (type) {
+       case CEPH_MSG_AUTH_REPLY:
+               handle_auth_reply(monc, msg);
+               break;
+
+       case CEPH_MSG_MON_SUBSCRIBE_ACK:
+               handle_subscribe_ack(monc, msg);
+               break;
+
+       case CEPH_MSG_STATFS_REPLY:
+               handle_statfs_reply(monc, msg);
+               break;
+
+       case CEPH_MSG_MON_MAP:
+               ceph_monc_handle_map(monc, msg);
+               break;
+
+       case CEPH_MSG_MDS_MAP:
+               ceph_mdsc_handle_map(&monc->client->mdsc, msg);
+               break;
+
+       case CEPH_MSG_OSD_MAP:
+               ceph_osdc_handle_map(&monc->client->osdc, msg);
+               break;
+
+       default:
+               pr_err("received unknown message type %d %s\n", type,
+                      ceph_msg_type_name(type));
+       }
+       ceph_msg_put(msg);
+}
+
+/*
+ * Allocate memory for incoming message
+ */
+static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
+                                     struct ceph_msg_header *hdr,
+                                     int *skip)
+{
+       struct ceph_mon_client *monc = con->private;
+       int type = le16_to_cpu(hdr->type);
+       int front_len = le32_to_cpu(hdr->front_len);
+       struct ceph_msg *m = NULL;
+
+       *skip = 0;
+
+       switch (type) {
+       case CEPH_MSG_MON_SUBSCRIBE_ACK:
+               m = ceph_msgpool_get(&monc->msgpool_subscribe_ack, front_len);
+               break;
+       case CEPH_MSG_STATFS_REPLY:
+               m = ceph_msgpool_get(&monc->msgpool_statfs_reply, front_len);
+               break;
+       case CEPH_MSG_AUTH_REPLY:
+               m = ceph_msgpool_get(&monc->msgpool_auth_reply, front_len);
+               break;
+       case CEPH_MSG_MON_MAP:
+       case CEPH_MSG_MDS_MAP:
+       case CEPH_MSG_OSD_MAP:
+               m = ceph_msg_new(type, front_len, 0, 0, NULL);
+               break;
+       }
+
+       if (!m) {
+               pr_info("alloc_msg unknown type %d\n", type);
+               *skip = 1;
+       }
+       return m;
+}
+
+/*
+ * If the monitor connection resets, pick a new monitor and resubmit
+ * any pending requests.
+ */
+static void mon_fault(struct ceph_connection *con)
+{
+       struct ceph_mon_client *monc = con->private;
+
+       if (!monc)
+               return;
+
+       dout("mon_fault\n");
+       mutex_lock(&monc->mutex);
+       if (!con->private)
+               goto out;
+
+       if (monc->con && !monc->hunting)
+               pr_info("mon%d %s session lost, "
+                       "hunting for new mon\n", monc->cur_mon,
+                       pr_addr(&monc->con->peer_addr.in_addr));
+
+       __close_session(monc);
+       if (!monc->hunting) {
+               /* start hunting */
+               monc->hunting = true;
+               __open_session(monc);
+       } else {
+               /* already hunting, let's wait a bit */
+               __schedule_delayed(monc);
+       }
+out:
+       mutex_unlock(&monc->mutex);
+}
+
+const static struct ceph_connection_operations mon_con_ops = {
+       .get = ceph_con_get,
+       .put = ceph_con_put,
+       .dispatch = dispatch,
+       .fault = mon_fault,
+       .alloc_msg = mon_alloc_msg,
+};
diff --git a/fs/ceph/mon_client.h b/fs/ceph/mon_client.h
new file mode 100644 (file)
index 0000000..b958ad5
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef _FS_CEPH_MON_CLIENT_H
+#define _FS_CEPH_MON_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/rbtree.h>
+
+#include "messenger.h"
+#include "msgpool.h"
+
+struct ceph_client;
+struct ceph_mount_args;
+struct ceph_auth_client;
+
+/*
+ * The monitor map enumerates the set of all monitors.
+ */
+struct ceph_monmap {
+       struct ceph_fsid fsid;
+       u32 epoch;
+       u32 num_mon;
+       struct ceph_entity_inst mon_inst[0];
+};
+
+struct ceph_mon_client;
+struct ceph_mon_statfs_request;
+
+
+/*
+ * Generic mechanism for resending monitor requests.
+ */
+typedef void (*ceph_monc_request_func_t)(struct ceph_mon_client *monc,
+                                        int newmon);
+
+/* a pending monitor request */
+struct ceph_mon_request {
+       struct ceph_mon_client *monc;
+       struct delayed_work delayed_work;
+       unsigned long delay;
+       ceph_monc_request_func_t do_request;
+};
+
+/*
+ * statfs() is done a bit differently because we need to get data back
+ * to the caller
+ */
+struct ceph_mon_statfs_request {
+       u64 tid;
+       struct rb_node node;
+       int result;
+       struct ceph_statfs *buf;
+       struct completion completion;
+       unsigned long last_attempt, delay; /* jiffies */
+       struct ceph_msg *request;  /* original request */
+};
+
+struct ceph_mon_client {
+       struct ceph_client *client;
+       struct ceph_monmap *monmap;
+
+       struct mutex mutex;
+       struct delayed_work delayed_work;
+
+       struct ceph_auth_client *auth;
+       struct ceph_msg *m_auth;
+       int pending_auth;
+
+       bool hunting;
+       int cur_mon;                       /* last monitor i contacted */
+       unsigned long sub_sent, sub_renew_after;
+       struct ceph_connection *con;
+       bool have_fsid;
+
+       /* msg pools */
+       struct ceph_msgpool msgpool_subscribe_ack;
+       struct ceph_msgpool msgpool_statfs_reply;
+       struct ceph_msgpool msgpool_auth_reply;
+
+       /* pending statfs requests */
+       struct rb_root statfs_request_tree;
+       int num_statfs_requests;
+       u64 last_tid;
+
+       /* mds/osd map */
+       int want_next_osdmap; /* 1 = want, 2 = want+asked */
+       u32 have_osdmap, have_mdsmap;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_file;
+#endif
+};
+
+extern struct ceph_monmap *ceph_monmap_decode(void *p, void *end);
+extern int ceph_monmap_contains(struct ceph_monmap *m,
+                               struct ceph_entity_addr *addr);
+
+extern int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl);
+extern void ceph_monc_stop(struct ceph_mon_client *monc);
+
+/*
+ * The model here is to indicate that we need a new map of at least
+ * epoch @want, and also call in when we receive a map.  We will
+ * periodically rerequest the map from the monitor cluster until we
+ * get what we want.
+ */
+extern int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 have);
+extern int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 have);
+
+extern void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc);
+
+extern int ceph_monc_do_statfs(struct ceph_mon_client *monc,
+                              struct ceph_statfs *buf);
+
+extern int ceph_monc_open_session(struct ceph_mon_client *monc);
+
+extern int ceph_monc_validate_auth(struct ceph_mon_client *monc);
+
+
+
+#endif
diff --git a/fs/ceph/msgpool.c b/fs/ceph/msgpool.c
new file mode 100644 (file)
index 0000000..ca3b44a
--- /dev/null
@@ -0,0 +1,186 @@
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include "msgpool.h"
+
+/*
+ * We use msg pools to preallocate memory for messages we expect to
+ * receive over the wire, to avoid getting ourselves into OOM
+ * conditions at unexpected times.  We take use a few different
+ * strategies:
+ *
+ *  - for request/response type interactions, we preallocate the
+ * memory needed for the response when we generate the request.
+ *
+ *  - for messages we can receive at any time from the MDS, we preallocate
+ * a pool of messages we can re-use.
+ *
+ *  - for writeback, we preallocate some number of messages to use for
+ * requests and their replies, so that we always make forward
+ * progress.
+ *
+ * The msgpool behaves like a mempool_t, but keeps preallocated
+ * ceph_msgs strung together on a list_head instead of using a pointer
+ * vector.  This avoids vector reallocation when we adjust the number
+ * of preallocated items (which happens frequently).
+ */
+
+
+/*
+ * Allocate or release as necessary to meet our target pool size.
+ */
+static int __fill_msgpool(struct ceph_msgpool *pool)
+{
+       struct ceph_msg *msg;
+
+       while (pool->num < pool->min) {
+               dout("fill_msgpool %p %d/%d allocating\n", pool, pool->num,
+                    pool->min);
+               spin_unlock(&pool->lock);
+               msg = ceph_msg_new(0, pool->front_len, 0, 0, NULL);
+               spin_lock(&pool->lock);
+               if (IS_ERR(msg))
+                       return PTR_ERR(msg);
+               msg->pool = pool;
+               list_add(&msg->list_head, &pool->msgs);
+               pool->num++;
+       }
+       while (pool->num > pool->min) {
+               msg = list_first_entry(&pool->msgs, struct ceph_msg, list_head);
+               dout("fill_msgpool %p %d/%d releasing %p\n", pool, pool->num,
+                    pool->min, msg);
+               list_del_init(&msg->list_head);
+               pool->num--;
+               ceph_msg_kfree(msg);
+       }
+       return 0;
+}
+
+int ceph_msgpool_init(struct ceph_msgpool *pool,
+                     int front_len, int min, bool blocking)
+{
+       int ret;
+
+       dout("msgpool_init %p front_len %d min %d\n", pool, front_len, min);
+       spin_lock_init(&pool->lock);
+       pool->front_len = front_len;
+       INIT_LIST_HEAD(&pool->msgs);
+       pool->num = 0;
+       pool->min = min;
+       pool->blocking = blocking;
+       init_waitqueue_head(&pool->wait);
+
+       spin_lock(&pool->lock);
+       ret = __fill_msgpool(pool);
+       spin_unlock(&pool->lock);
+       return ret;
+}
+
+void ceph_msgpool_destroy(struct ceph_msgpool *pool)
+{
+       dout("msgpool_destroy %p\n", pool);
+       spin_lock(&pool->lock);
+       pool->min = 0;
+       __fill_msgpool(pool);
+       spin_unlock(&pool->lock);
+}
+
+int ceph_msgpool_resv(struct ceph_msgpool *pool, int delta)
+{
+       int ret;
+
+       spin_lock(&pool->lock);
+       dout("msgpool_resv %p delta %d\n", pool, delta);
+       pool->min += delta;
+       ret = __fill_msgpool(pool);
+       spin_unlock(&pool->lock);
+       return ret;
+}
+
+struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, int front_len)
+{
+       wait_queue_t wait;
+       struct ceph_msg *msg;
+
+       if (front_len && front_len > pool->front_len) {
+               pr_err("msgpool_get pool %p need front %d, pool size is %d\n",
+                      pool, front_len, pool->front_len);
+               WARN_ON(1);
+
+               /* try to alloc a fresh message */
+               msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+               if (!IS_ERR(msg))
+                       return msg;
+       }
+
+       if (!front_len)
+               front_len = pool->front_len;
+
+       if (pool->blocking) {
+               /* mempool_t behavior; first try to alloc */
+               msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+               if (!IS_ERR(msg))
+                       return msg;
+       }
+
+       while (1) {
+               spin_lock(&pool->lock);
+               if (likely(pool->num)) {
+                       msg = list_entry(pool->msgs.next, struct ceph_msg,
+                                        list_head);
+                       list_del_init(&msg->list_head);
+                       pool->num--;
+                       dout("msgpool_get %p got %p, now %d/%d\n", pool, msg,
+                            pool->num, pool->min);
+                       spin_unlock(&pool->lock);
+                       return msg;
+               }
+               pr_err("msgpool_get %p now %d/%d, %s\n", pool, pool->num,
+                      pool->min, pool->blocking ? "waiting" : "may fail");
+               spin_unlock(&pool->lock);
+
+               if (!pool->blocking) {
+                       WARN_ON(1);
+
+                       /* maybe we can allocate it now? */
+                       msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+                       if (!IS_ERR(msg))
+                               return msg;
+
+                       pr_err("msgpool_get %p empty + alloc failed\n", pool);
+                       return ERR_PTR(-ENOMEM);
+               }
+
+               init_wait(&wait);
+               prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
+               schedule();
+               finish_wait(&pool->wait, &wait);
+       }
+}
+
+void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
+{
+       spin_lock(&pool->lock);
+       if (pool->num < pool->min) {
+               /* reset msg front_len; user may have changed it */
+               msg->front.iov_len = pool->front_len;
+               msg->hdr.front_len = cpu_to_le32(pool->front_len);
+
+               kref_set(&msg->kref, 1);  /* retake a single ref */
+               list_add(&msg->list_head, &pool->msgs);
+               pool->num++;
+               dout("msgpool_put %p reclaim %p, now %d/%d\n", pool, msg,
+                    pool->num, pool->min);
+               spin_unlock(&pool->lock);
+               wake_up(&pool->wait);
+       } else {
+               dout("msgpool_put %p drop %p, at %d/%d\n", pool, msg,
+                    pool->num, pool->min);
+               spin_unlock(&pool->lock);
+               ceph_msg_kfree(msg);
+       }
+}
diff --git a/fs/ceph/msgpool.h b/fs/ceph/msgpool.h
new file mode 100644 (file)
index 0000000..bc834bf
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _FS_CEPH_MSGPOOL
+#define _FS_CEPH_MSGPOOL
+
+#include "messenger.h"
+
+/*
+ * we use memory pools for preallocating messages we may receive, to
+ * avoid unexpected OOM conditions.
+ */
+struct ceph_msgpool {
+       spinlock_t lock;
+       int front_len;          /* preallocated payload size */
+       struct list_head msgs;  /* msgs in the pool; each has 1 ref */
+       int num, min;           /* cur, min # msgs in the pool */
+       bool blocking;
+       wait_queue_head_t wait;
+};
+
+extern int ceph_msgpool_init(struct ceph_msgpool *pool,
+                            int front_len, int size, bool blocking);
+extern void ceph_msgpool_destroy(struct ceph_msgpool *pool);
+extern int ceph_msgpool_resv(struct ceph_msgpool *, int delta);
+extern struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *,
+                                        int front_len);
+extern void ceph_msgpool_put(struct ceph_msgpool *, struct ceph_msg *);
+
+#endif
diff --git a/fs/ceph/msgr.h b/fs/ceph/msgr.h
new file mode 100644 (file)
index 0000000..8aaab41
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef __MSGR_H
+#define __MSGR_H
+
+/*
+ * Data types for message passing layer used by Ceph.
+ */
+
+#define CEPH_MON_PORT    6789  /* default monitor port */
+
+/*
+ * client-side processes will try to bind to ports in this
+ * range, simply for the benefit of tools like nmap or wireshark
+ * that would like to identify the protocol.
+ */
+#define CEPH_PORT_FIRST  6789
+#define CEPH_PORT_START  6800  /* non-monitors start here */
+#define CEPH_PORT_LAST   6900
+
+/*
+ * tcp connection banner.  include a protocol version. and adjust
+ * whenever the wire protocol changes.  try to keep this string length
+ * constant.
+ */
+#define CEPH_BANNER "ceph v027"
+#define CEPH_BANNER_MAX_LEN 30
+
+
+/*
+ * Rollover-safe type and comparator for 32-bit sequence numbers.
+ * Comparator returns -1, 0, or 1.
+ */
+typedef __u32 ceph_seq_t;
+
+static inline __s32 ceph_seq_cmp(__u32 a, __u32 b)
+{
+       return (__s32)a - (__s32)b;
+}
+
+
+/*
+ * entity_name -- logical name for a process participating in the
+ * network, e.g. 'mds0' or 'osd3'.
+ */
+struct ceph_entity_name {
+       __u8 type;      /* CEPH_ENTITY_TYPE_* */
+       __le64 num;
+} __attribute__ ((packed));
+
+#define CEPH_ENTITY_TYPE_MON    0x01
+#define CEPH_ENTITY_TYPE_MDS    0x02
+#define CEPH_ENTITY_TYPE_OSD    0x04
+#define CEPH_ENTITY_TYPE_CLIENT 0x08
+#define CEPH_ENTITY_TYPE_ADMIN  0x10
+#define CEPH_ENTITY_TYPE_AUTH   0x20
+
+#define CEPH_ENTITY_TYPE_ANY    0xFF
+
+extern const char *ceph_entity_type_name(int type);
+
+/*
+ * entity_addr -- network address
+ */
+struct ceph_entity_addr {
+       __le32 type;
+       __le32 nonce;  /* unique id for process (e.g. pid) */
+       struct sockaddr_storage in_addr;
+} __attribute__ ((packed));
+
+struct ceph_entity_inst {
+       struct ceph_entity_name name;
+       struct ceph_entity_addr addr;
+} __attribute__ ((packed));
+
+
+/* used by message exchange protocol */
+#define CEPH_MSGR_TAG_READY         1  /* server->client: ready for messages */
+#define CEPH_MSGR_TAG_RESETSESSION  2  /* server->client: reset, try again */
+#define CEPH_MSGR_TAG_WAIT          3  /* server->client: wait for racing
+                                         incoming connection */
+#define CEPH_MSGR_TAG_RETRY_SESSION 4  /* server->client + cseq: try again
+                                         with higher cseq */
+#define CEPH_MSGR_TAG_RETRY_GLOBAL  5  /* server->client + gseq: try again
+                                         with higher gseq */
+#define CEPH_MSGR_TAG_CLOSE         6  /* closing pipe */
+#define CEPH_MSGR_TAG_MSG           7  /* message */
+#define CEPH_MSGR_TAG_ACK           8  /* message ack */
+#define CEPH_MSGR_TAG_KEEPALIVE     9  /* just a keepalive byte! */
+#define CEPH_MSGR_TAG_BADPROTOVER  10  /* bad protocol version */
+#define CEPH_MSGR_TAG_BADAUTHORIZER 11 /* bad authorizer */
+#define CEPH_MSGR_TAG_FEATURES      12 /* insufficient features */
+
+
+/*
+ * connection negotiation
+ */
+struct ceph_msg_connect {
+       __le64 features;     /* supported feature bits */
+       __le32 host_type;    /* CEPH_ENTITY_TYPE_* */
+       __le32 global_seq;   /* count connections initiated by this host */
+       __le32 connect_seq;  /* count connections initiated in this session */
+       __le32 protocol_version;
+       __le32 authorizer_protocol;
+       __le32 authorizer_len;
+       __u8  flags;         /* CEPH_MSG_CONNECT_* */
+} __attribute__ ((packed));
+
+struct ceph_msg_connect_reply {
+       __u8 tag;
+       __le64 features;     /* feature bits for this session */
+       __le32 global_seq;
+       __le32 connect_seq;
+       __le32 protocol_version;
+       __le32 authorizer_len;
+       __u8 flags;
+} __attribute__ ((packed));
+
+#define CEPH_MSG_CONNECT_LOSSY  1  /* messages i send may be safely dropped */
+
+
+/*
+ * message header
+ */
+struct ceph_msg_header {
+       __le64 seq;       /* message seq# for this session */
+       __le64 tid;       /* transaction id */
+       __le16 type;      /* message type */
+       __le16 priority;  /* priority.  higher value == higher priority */
+       __le16 version;   /* version of message encoding */
+
+       __le32 front_len; /* bytes in main payload */
+       __le32 middle_len;/* bytes in middle payload */
+       __le32 data_len;  /* bytes of data payload */
+       __le16 data_off;  /* sender: include full offset;
+                            receiver: mask against ~PAGE_MASK */
+
+       struct ceph_entity_inst src, orig_src;
+       __le32 reserved;
+       __le32 crc;       /* header crc32c */
+} __attribute__ ((packed));
+
+#define CEPH_MSG_PRIO_LOW     64
+#define CEPH_MSG_PRIO_DEFAULT 127
+#define CEPH_MSG_PRIO_HIGH    196
+#define CEPH_MSG_PRIO_HIGHEST 255
+
+/*
+ * follows data payload
+ */
+struct ceph_msg_footer {
+       __le32 front_crc, middle_crc, data_crc;
+       __u8 flags;
+} __attribute__ ((packed));
+
+#define CEPH_MSG_FOOTER_COMPLETE  (1<<0)   /* msg wasn't aborted */
+#define CEPH_MSG_FOOTER_NOCRC     (1<<1)   /* no data crc */
+
+
+#endif
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c
new file mode 100644 (file)
index 0000000..dbe63db
--- /dev/null
@@ -0,0 +1,1537 @@
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "super.h"
+#include "osd_client.h"
+#include "messenger.h"
+#include "decode.h"
+#include "auth.h"
+
+#define OSD_OP_FRONT_LEN       4096
+#define OSD_OPREPLY_FRONT_LEN  512
+
+const static struct ceph_connection_operations osd_con_ops;
+static int __kick_requests(struct ceph_osd_client *osdc,
+                         struct ceph_osd *kickosd);
+
+static void kick_requests(struct ceph_osd_client *osdc, struct ceph_osd *osd);
+
+/*
+ * Implement client access to distributed object storage cluster.
+ *
+ * All data objects are stored within a cluster/cloud of OSDs, or
+ * "object storage devices."  (Note that Ceph OSDs have _nothing_ to
+ * do with the T10 OSD extensions to SCSI.)  Ceph OSDs are simply
+ * remote daemons serving up and coordinating consistent and safe
+ * access to storage.
+ *
+ * Cluster membership and the mapping of data objects onto storage devices
+ * are described by the osd map.
+ *
+ * We keep track of pending OSD requests (read, write), resubmit
+ * requests to different OSDs when the cluster topology/data layout
+ * change, or retry the affected requests when the communications
+ * channel with an OSD is reset.
+ */
+
+/*
+ * calculate the mapping of a file extent onto an object, and fill out the
+ * request accordingly.  shorten extent as necessary if it crosses an
+ * object boundary.
+ *
+ * fill osd op in request message.
+ */
+static void calc_layout(struct ceph_osd_client *osdc,
+                       struct ceph_vino vino, struct ceph_file_layout *layout,
+                       u64 off, u64 *plen,
+                       struct ceph_osd_request *req)
+{
+       struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
+       struct ceph_osd_op *op = (void *)(reqhead + 1);
+       u64 orig_len = *plen;
+       u64 objoff, objlen;    /* extent in object */
+       u64 bno;
+
+       reqhead->snapid = cpu_to_le64(vino.snap);
+
+       /* object extent? */
+       ceph_calc_file_object_mapping(layout, off, plen, &bno,
+                                     &objoff, &objlen);
+       if (*plen < orig_len)
+               dout(" skipping last %llu, final file extent %llu~%llu\n",
+                    orig_len - *plen, off, *plen);
+
+       sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno);
+       req->r_oid_len = strlen(req->r_oid);
+
+       op->extent.offset = cpu_to_le64(objoff);
+       op->extent.length = cpu_to_le64(objlen);
+       req->r_num_pages = calc_pages_for(off, *plen);
+
+       dout("calc_layout %s (%d) %llu~%llu (%d pages)\n",
+            req->r_oid, req->r_oid_len, objoff, objlen, req->r_num_pages);
+}
+
+/*
+ * requests
+ */
+void ceph_osdc_release_request(struct kref *kref)
+{
+       struct ceph_osd_request *req = container_of(kref,
+                                                   struct ceph_osd_request,
+                                                   r_kref);
+
+       if (req->r_request)
+               ceph_msg_put(req->r_request);
+       if (req->r_reply)
+               ceph_msg_put(req->r_reply);
+       if (req->r_con_filling_msg) {
+               dout("release_request revoking pages %p from con %p\n",
+                    req->r_pages, req->r_con_filling_msg);
+               ceph_con_revoke_message(req->r_con_filling_msg,
+                                     req->r_reply);
+               ceph_con_put(req->r_con_filling_msg);
+       }
+       if (req->r_own_pages)
+               ceph_release_page_vector(req->r_pages,
+                                        req->r_num_pages);
+       ceph_put_snap_context(req->r_snapc);
+       if (req->r_mempool)
+               mempool_free(req, req->r_osdc->req_mempool);
+       else
+               kfree(req);
+}
+
+/*
+ * build new request AND message, calculate layout, and adjust file
+ * extent as needed.
+ *
+ * if the file was recently truncated, we include information about its
+ * old and new size so that the object can be updated appropriately.  (we
+ * avoid synchronously deleting truncated objects because it's slow.)
+ *
+ * if @do_sync, include a 'startsync' command so that the osd will flush
+ * data quickly.
+ */
+struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
+                                              struct ceph_file_layout *layout,
+                                              struct ceph_vino vino,
+                                              u64 off, u64 *plen,
+                                              int opcode, int flags,
+                                              struct ceph_snap_context *snapc,
+                                              int do_sync,
+                                              u32 truncate_seq,
+                                              u64 truncate_size,
+                                              struct timespec *mtime,
+                                              bool use_mempool, int num_reply)
+{
+       struct ceph_osd_request *req;
+       struct ceph_msg *msg;
+       struct ceph_osd_request_head *head;
+       struct ceph_osd_op *op;
+       void *p;
+       int num_op = 1 + do_sync;
+       size_t msg_size = sizeof(*head) + num_op*sizeof(*op);
+       int i;
+
+       if (use_mempool) {
+               req = mempool_alloc(osdc->req_mempool, GFP_NOFS);
+               memset(req, 0, sizeof(*req));
+       } else {
+               req = kzalloc(sizeof(*req), GFP_NOFS);
+       }
+       if (req == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       req->r_osdc = osdc;
+       req->r_mempool = use_mempool;
+       kref_init(&req->r_kref);
+       init_completion(&req->r_completion);
+       init_completion(&req->r_safe_completion);
+       INIT_LIST_HEAD(&req->r_unsafe_item);
+       req->r_flags = flags;
+
+       WARN_ON((flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == 0);
+
+       /* create reply message */
+       if (use_mempool)
+               msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
+       else
+               msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY,
+                                  OSD_OPREPLY_FRONT_LEN, 0, 0, NULL);
+       if (IS_ERR(msg)) {
+               ceph_osdc_put_request(req);
+               return ERR_PTR(PTR_ERR(msg));
+       }
+       req->r_reply = msg;
+
+       /* create request message; allow space for oid */
+       msg_size += 40;
+       if (snapc)
+               msg_size += sizeof(u64) * snapc->num_snaps;
+       if (use_mempool)
+               msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
+       else
+               msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, 0, 0, NULL);
+       if (IS_ERR(msg)) {
+               ceph_osdc_put_request(req);
+               return ERR_PTR(PTR_ERR(msg));
+       }
+       msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP);
+       memset(msg->front.iov_base, 0, msg->front.iov_len);
+       head = msg->front.iov_base;
+       op = (void *)(head + 1);
+       p = (void *)(op + num_op);
+
+       req->r_request = msg;
+       req->r_snapc = ceph_get_snap_context(snapc);
+
+       head->client_inc = cpu_to_le32(1); /* always, for now. */
+       head->flags = cpu_to_le32(flags);
+       if (flags & CEPH_OSD_FLAG_WRITE)
+               ceph_encode_timespec(&head->mtime, mtime);
+       head->num_ops = cpu_to_le16(num_op);
+       op->op = cpu_to_le16(opcode);
+
+       /* calculate max write size */
+       calc_layout(osdc, vino, layout, off, plen, req);
+       req->r_file_layout = *layout;  /* keep a copy */
+
+       if (flags & CEPH_OSD_FLAG_WRITE) {
+               req->r_request->hdr.data_off = cpu_to_le16(off);
+               req->r_request->hdr.data_len = cpu_to_le32(*plen);
+               op->payload_len = cpu_to_le32(*plen);
+       }
+       op->extent.truncate_size = cpu_to_le64(truncate_size);
+       op->extent.truncate_seq = cpu_to_le32(truncate_seq);
+
+       /* fill in oid */
+       head->object_len = cpu_to_le32(req->r_oid_len);
+       memcpy(p, req->r_oid, req->r_oid_len);
+       p += req->r_oid_len;
+
+       if (do_sync) {
+               op++;
+               op->op = cpu_to_le16(CEPH_OSD_OP_STARTSYNC);
+       }
+       if (snapc) {
+               head->snap_seq = cpu_to_le64(snapc->seq);
+               head->num_snaps = cpu_to_le32(snapc->num_snaps);
+               for (i = 0; i < snapc->num_snaps; i++) {
+                       put_unaligned_le64(snapc->snaps[i], p);
+                       p += sizeof(u64);
+               }
+       }
+
+       BUG_ON(p > msg->front.iov_base + msg->front.iov_len);
+       msg_size = p - msg->front.iov_base;
+       msg->front.iov_len = msg_size;
+       msg->hdr.front_len = cpu_to_le32(msg_size);
+       return req;
+}
+
+/*
+ * We keep osd requests in an rbtree, sorted by ->r_tid.
+ */
+static void __insert_request(struct ceph_osd_client *osdc,
+                            struct ceph_osd_request *new)
+{
+       struct rb_node **p = &osdc->requests.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_osd_request *req = NULL;
+
+       while (*p) {
+               parent = *p;
+               req = rb_entry(parent, struct ceph_osd_request, r_node);
+               if (new->r_tid < req->r_tid)
+                       p = &(*p)->rb_left;
+               else if (new->r_tid > req->r_tid)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->r_node, parent, p);
+       rb_insert_color(&new->r_node, &osdc->requests);
+}
+
+static struct ceph_osd_request *__lookup_request(struct ceph_osd_client *osdc,
+                                                u64 tid)
+{
+       struct ceph_osd_request *req;
+       struct rb_node *n = osdc->requests.rb_node;
+
+       while (n) {
+               req = rb_entry(n, struct ceph_osd_request, r_node);
+               if (tid < req->r_tid)
+                       n = n->rb_left;
+               else if (tid > req->r_tid)
+                       n = n->rb_right;
+               else
+                       return req;
+       }
+       return NULL;
+}
+
+static struct ceph_osd_request *
+__lookup_request_ge(struct ceph_osd_client *osdc,
+                   u64 tid)
+{
+       struct ceph_osd_request *req;
+       struct rb_node *n = osdc->requests.rb_node;
+
+       while (n) {
+               req = rb_entry(n, struct ceph_osd_request, r_node);
+               if (tid < req->r_tid) {
+                       if (!n->rb_left)
+                               return req;
+                       n = n->rb_left;
+               } else if (tid > req->r_tid) {
+                       n = n->rb_right;
+               } else {
+                       return req;
+               }
+       }
+       return NULL;
+}
+
+
+/*
+ * If the osd connection drops, we need to resubmit all requests.
+ */
+static void osd_reset(struct ceph_connection *con)
+{
+       struct ceph_osd *osd = con->private;
+       struct ceph_osd_client *osdc;
+
+       if (!osd)
+               return;
+       dout("osd_reset osd%d\n", osd->o_osd);
+       osdc = osd->o_osdc;
+       down_read(&osdc->map_sem);
+       kick_requests(osdc, osd);
+       up_read(&osdc->map_sem);
+}
+
+/*
+ * Track open sessions with osds.
+ */
+static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
+{
+       struct ceph_osd *osd;
+
+       osd = kzalloc(sizeof(*osd), GFP_NOFS);
+       if (!osd)
+               return NULL;
+
+       atomic_set(&osd->o_ref, 1);
+       osd->o_osdc = osdc;
+       INIT_LIST_HEAD(&osd->o_requests);
+       INIT_LIST_HEAD(&osd->o_osd_lru);
+       osd->o_incarnation = 1;
+
+       ceph_con_init(osdc->client->msgr, &osd->o_con);
+       osd->o_con.private = osd;
+       osd->o_con.ops = &osd_con_ops;
+       osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD;
+
+       INIT_LIST_HEAD(&osd->o_keepalive_item);
+       return osd;
+}
+
+static struct ceph_osd *get_osd(struct ceph_osd *osd)
+{
+       if (atomic_inc_not_zero(&osd->o_ref)) {
+               dout("get_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref)-1,
+                    atomic_read(&osd->o_ref));
+               return osd;
+       } else {
+               dout("get_osd %p FAIL\n", osd);
+               return NULL;
+       }
+}
+
+static void put_osd(struct ceph_osd *osd)
+{
+       dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref),
+            atomic_read(&osd->o_ref) - 1);
+       if (atomic_dec_and_test(&osd->o_ref))
+               kfree(osd);
+}
+
+/*
+ * remove an osd from our map
+ */
+static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
+{
+       dout("__remove_osd %p\n", osd);
+       BUG_ON(!list_empty(&osd->o_requests));
+       rb_erase(&osd->o_node, &osdc->osds);
+       list_del_init(&osd->o_osd_lru);
+       ceph_con_close(&osd->o_con);
+       put_osd(osd);
+}
+
+static void __move_osd_to_lru(struct ceph_osd_client *osdc,
+                             struct ceph_osd *osd)
+{
+       dout("__move_osd_to_lru %p\n", osd);
+       BUG_ON(!list_empty(&osd->o_osd_lru));
+       list_add_tail(&osd->o_osd_lru, &osdc->osd_lru);
+       osd->lru_ttl = jiffies + osdc->client->mount_args->osd_idle_ttl * HZ;
+}
+
+static void __remove_osd_from_lru(struct ceph_osd *osd)
+{
+       dout("__remove_osd_from_lru %p\n", osd);
+       if (!list_empty(&osd->o_osd_lru))
+               list_del_init(&osd->o_osd_lru);
+}
+
+static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all)
+{
+       struct ceph_osd *osd, *nosd;
+
+       dout("__remove_old_osds %p\n", osdc);
+       mutex_lock(&osdc->request_mutex);
+       list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) {
+               if (!remove_all && time_before(jiffies, osd->lru_ttl))
+                       break;
+               __remove_osd(osdc, osd);
+       }
+       mutex_unlock(&osdc->request_mutex);
+}
+
+/*
+ * reset osd connect
+ */
+static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
+{
+       int ret = 0;
+
+       dout("__reset_osd %p osd%d\n", osd, osd->o_osd);
+       if (list_empty(&osd->o_requests)) {
+               __remove_osd(osdc, osd);
+       } else {
+               ceph_con_close(&osd->o_con);
+               ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]);
+               osd->o_incarnation++;
+       }
+       return ret;
+}
+
+static void __insert_osd(struct ceph_osd_client *osdc, struct ceph_osd *new)
+{
+       struct rb_node **p = &osdc->osds.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_osd *osd = NULL;
+
+       while (*p) {
+               parent = *p;
+               osd = rb_entry(parent, struct ceph_osd, o_node);
+               if (new->o_osd < osd->o_osd)
+                       p = &(*p)->rb_left;
+               else if (new->o_osd > osd->o_osd)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->o_node, parent, p);
+       rb_insert_color(&new->o_node, &osdc->osds);
+}
+
+static struct ceph_osd *__lookup_osd(struct ceph_osd_client *osdc, int o)
+{
+       struct ceph_osd *osd;
+       struct rb_node *n = osdc->osds.rb_node;
+
+       while (n) {
+               osd = rb_entry(n, struct ceph_osd, o_node);
+               if (o < osd->o_osd)
+                       n = n->rb_left;
+               else if (o > osd->o_osd)
+                       n = n->rb_right;
+               else
+                       return osd;
+       }
+       return NULL;
+}
+
+static void __schedule_osd_timeout(struct ceph_osd_client *osdc)
+{
+       schedule_delayed_work(&osdc->timeout_work,
+                       osdc->client->mount_args->osd_keepalive_timeout * HZ);
+}
+
+static void __cancel_osd_timeout(struct ceph_osd_client *osdc)
+{
+       cancel_delayed_work(&osdc->timeout_work);
+}
+
+/*
+ * Register request, assign tid.  If this is the first request, set up
+ * the timeout event.
+ */
+static void register_request(struct ceph_osd_client *osdc,
+                            struct ceph_osd_request *req)
+{
+       mutex_lock(&osdc->request_mutex);
+       req->r_tid = ++osdc->last_tid;
+       req->r_request->hdr.tid = cpu_to_le64(req->r_tid);
+       INIT_LIST_HEAD(&req->r_req_lru_item);
+
+       dout("register_request %p tid %lld\n", req, req->r_tid);
+       __insert_request(osdc, req);
+       ceph_osdc_get_request(req);
+       osdc->num_requests++;
+
+       if (osdc->num_requests == 1) {
+               dout(" first request, scheduling timeout\n");
+               __schedule_osd_timeout(osdc);
+       }
+       mutex_unlock(&osdc->request_mutex);
+}
+
+/*
+ * called under osdc->request_mutex
+ */
+static void __unregister_request(struct ceph_osd_client *osdc,
+                                struct ceph_osd_request *req)
+{
+       dout("__unregister_request %p tid %lld\n", req, req->r_tid);
+       rb_erase(&req->r_node, &osdc->requests);
+       osdc->num_requests--;
+
+       if (req->r_osd) {
+               /* make sure the original request isn't in flight. */
+               ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+
+               list_del_init(&req->r_osd_item);
+               if (list_empty(&req->r_osd->o_requests))
+                       __move_osd_to_lru(osdc, req->r_osd);
+               req->r_osd = NULL;
+       }
+
+       ceph_osdc_put_request(req);
+
+       list_del_init(&req->r_req_lru_item);
+       if (osdc->num_requests == 0) {
+               dout(" no requests, canceling timeout\n");
+               __cancel_osd_timeout(osdc);
+       }
+}
+
+/*
+ * Cancel a previously queued request message
+ */
+static void __cancel_request(struct ceph_osd_request *req)
+{
+       if (req->r_sent) {
+               ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+               req->r_sent = 0;
+       }
+       list_del_init(&req->r_req_lru_item);
+}
+
+/*
+ * Pick an osd (the first 'up' osd in the pg), allocate the osd struct
+ * (as needed), and set the request r_osd appropriately.  If there is
+ * no up osd, set r_osd to NULL.
+ *
+ * Return 0 if unchanged, 1 if changed, or negative on error.
+ *
+ * Caller should hold map_sem for read and request_mutex.
+ */
+static int __map_osds(struct ceph_osd_client *osdc,
+                     struct ceph_osd_request *req)
+{
+       struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
+       struct ceph_pg pgid;
+       int o = -1;
+       int err;
+
+       dout("map_osds %p tid %lld\n", req, req->r_tid);
+       err = ceph_calc_object_layout(&reqhead->layout, req->r_oid,
+                                     &req->r_file_layout, osdc->osdmap);
+       if (err)
+               return err;
+       pgid = reqhead->layout.ol_pgid;
+       req->r_pgid = pgid;
+
+       o = ceph_calc_pg_primary(osdc->osdmap, pgid);
+
+       if ((req->r_osd && req->r_osd->o_osd == o &&
+            req->r_sent >= req->r_osd->o_incarnation) ||
+           (req->r_osd == NULL && o == -1))
+               return 0;  /* no change */
+
+       dout("map_osds tid %llu pgid %d.%x osd%d (was osd%d)\n",
+            req->r_tid, le32_to_cpu(pgid.pool), le16_to_cpu(pgid.ps), o,
+            req->r_osd ? req->r_osd->o_osd : -1);
+
+       if (req->r_osd) {
+               __cancel_request(req);
+               list_del_init(&req->r_osd_item);
+               req->r_osd = NULL;
+       }
+
+       req->r_osd = __lookup_osd(osdc, o);
+       if (!req->r_osd && o >= 0) {
+               err = -ENOMEM;
+               req->r_osd = create_osd(osdc);
+               if (!req->r_osd)
+                       goto out;
+
+               dout("map_osds osd %p is osd%d\n", req->r_osd, o);
+               req->r_osd->o_osd = o;
+               req->r_osd->o_con.peer_name.num = cpu_to_le64(o);
+               __insert_osd(osdc, req->r_osd);
+
+               ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]);
+       }
+
+       if (req->r_osd) {
+               __remove_osd_from_lru(req->r_osd);
+               list_add(&req->r_osd_item, &req->r_osd->o_requests);
+       }
+       err = 1;   /* osd changed */
+
+out:
+       return err;
+}
+
+/*
+ * caller should hold map_sem (for read) and request_mutex
+ */
+static int __send_request(struct ceph_osd_client *osdc,
+                         struct ceph_osd_request *req)
+{
+       struct ceph_osd_request_head *reqhead;
+       int err;
+
+       err = __map_osds(osdc, req);
+       if (err < 0)
+               return err;
+       if (req->r_osd == NULL) {
+               dout("send_request %p no up osds in pg\n", req);
+               ceph_monc_request_next_osdmap(&osdc->client->monc);
+               return 0;
+       }
+
+       dout("send_request %p tid %llu to osd%d flags %d\n",
+            req, req->r_tid, req->r_osd->o_osd, req->r_flags);
+
+       reqhead = req->r_request->front.iov_base;
+       reqhead->osdmap_epoch = cpu_to_le32(osdc->osdmap->epoch);
+       reqhead->flags |= cpu_to_le32(req->r_flags);  /* e.g., RETRY */
+       reqhead->reassert_version = req->r_reassert_version;
+
+       req->r_sent_stamp = jiffies;
+       list_move_tail(&osdc->req_lru, &req->r_req_lru_item);
+
+       ceph_msg_get(req->r_request); /* send consumes a ref */
+       ceph_con_send(&req->r_osd->o_con, req->r_request);
+       req->r_sent = req->r_osd->o_incarnation;
+       return 0;
+}
+
+/*
+ * Timeout callback, called every N seconds when 1 or more osd
+ * requests has been active for more than N seconds.  When this
+ * happens, we ping all OSDs with requests who have timed out to
+ * ensure any communications channel reset is detected.  Reset the
+ * request timeouts another N seconds in the future as we go.
+ * Reschedule the timeout event another N seconds in future (unless
+ * there are no open requests).
+ */
+static void handle_timeout(struct work_struct *work)
+{
+       struct ceph_osd_client *osdc =
+               container_of(work, struct ceph_osd_client, timeout_work.work);
+       struct ceph_osd_request *req, *last_req = NULL;
+       struct ceph_osd *osd;
+       unsigned long timeout = osdc->client->mount_args->osd_timeout * HZ;
+       unsigned long keepalive =
+               osdc->client->mount_args->osd_keepalive_timeout * HZ;
+       unsigned long last_sent = 0;
+       struct rb_node *p;
+       struct list_head slow_osds;
+
+       dout("timeout\n");
+       down_read(&osdc->map_sem);
+
+       ceph_monc_request_next_osdmap(&osdc->client->monc);
+
+       mutex_lock(&osdc->request_mutex);
+       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+               req = rb_entry(p, struct ceph_osd_request, r_node);
+
+               if (req->r_resend) {
+                       int err;
+
+                       dout("osdc resending prev failed %lld\n", req->r_tid);
+                       err = __send_request(osdc, req);
+                       if (err)
+                               dout("osdc failed again on %lld\n", req->r_tid);
+                       else
+                               req->r_resend = false;
+                       continue;
+               }
+       }
+
+       /*
+        * reset osds that appear to be _really_ unresponsive.  this
+        * is a failsafe measure.. we really shouldn't be getting to
+        * this point if the system is working properly.  the monitors
+        * should mark the osd as failed and we should find out about
+        * it from an updated osd map.
+        */
+       while (!list_empty(&osdc->req_lru)) {
+               req = list_entry(osdc->req_lru.next, struct ceph_osd_request,
+                                r_req_lru_item);
+
+               if (time_before(jiffies, req->r_sent_stamp + timeout))
+                       break;
+
+               BUG_ON(req == last_req && req->r_sent_stamp == last_sent);
+               last_req = req;
+               last_sent = req->r_sent_stamp;
+
+               osd = req->r_osd;
+               BUG_ON(!osd);
+               pr_warning(" tid %llu timed out on osd%d, will reset osd\n",
+                          req->r_tid, osd->o_osd);
+               __kick_requests(osdc, osd);
+       }
+
+       /*
+        * ping osds that are a bit slow.  this ensures that if there
+        * is a break in the TCP connection we will notice, and reopen
+        * a connection with that osd (from the fault callback).
+        */
+       INIT_LIST_HEAD(&slow_osds);
+       list_for_each_entry(req, &osdc->req_lru, r_req_lru_item) {
+               if (time_before(jiffies, req->r_sent_stamp + keepalive))
+                       break;
+
+               osd = req->r_osd;
+               BUG_ON(!osd);
+               dout(" tid %llu is slow, will send keepalive on osd%d\n",
+                    req->r_tid, osd->o_osd);
+               list_move_tail(&osd->o_keepalive_item, &slow_osds);
+       }
+       while (!list_empty(&slow_osds)) {
+               osd = list_entry(slow_osds.next, struct ceph_osd,
+                                o_keepalive_item);
+               list_del_init(&osd->o_keepalive_item);
+               ceph_con_keepalive(&osd->o_con);
+       }
+
+       __schedule_osd_timeout(osdc);
+       mutex_unlock(&osdc->request_mutex);
+
+       up_read(&osdc->map_sem);
+}
+
+static void handle_osds_timeout(struct work_struct *work)
+{
+       struct ceph_osd_client *osdc =
+               container_of(work, struct ceph_osd_client,
+                            osds_timeout_work.work);
+       unsigned long delay =
+               osdc->client->mount_args->osd_idle_ttl * HZ >> 2;
+
+       dout("osds timeout\n");
+       down_read(&osdc->map_sem);
+       remove_old_osds(osdc, 0);
+       up_read(&osdc->map_sem);
+
+       schedule_delayed_work(&osdc->osds_timeout_work,
+                             round_jiffies_relative(delay));
+}
+
+/*
+ * handle osd op reply.  either call the callback if it is specified,
+ * or do the completion to wake up the waiting thread.
+ */
+static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
+                        struct ceph_connection *con)
+{
+       struct ceph_osd_reply_head *rhead = msg->front.iov_base;
+       struct ceph_osd_request *req;
+       u64 tid;
+       int numops, object_len, flags;
+
+       tid = le64_to_cpu(msg->hdr.tid);
+       if (msg->front.iov_len < sizeof(*rhead))
+               goto bad;
+       numops = le32_to_cpu(rhead->num_ops);
+       object_len = le32_to_cpu(rhead->object_len);
+       if (msg->front.iov_len != sizeof(*rhead) + object_len +
+           numops * sizeof(struct ceph_osd_op))
+               goto bad;
+       dout("handle_reply %p tid %llu\n", msg, tid);
+
+       /* lookup */
+       mutex_lock(&osdc->request_mutex);
+       req = __lookup_request(osdc, tid);
+       if (req == NULL) {
+               dout("handle_reply tid %llu dne\n", tid);
+               mutex_unlock(&osdc->request_mutex);
+               return;
+       }
+       ceph_osdc_get_request(req);
+       flags = le32_to_cpu(rhead->flags);
+
+       /*
+        * if this connection filled our message, drop our reference now, to
+        * avoid a (safe but slower) revoke later.
+        */
+       if (req->r_con_filling_msg == con && req->r_reply == msg) {
+               dout(" dropping con_filling_msg ref %p\n", con);
+               req->r_con_filling_msg = NULL;
+               ceph_con_put(con);
+       }
+
+       if (!req->r_got_reply) {
+               unsigned bytes;
+
+               req->r_result = le32_to_cpu(rhead->result);
+               bytes = le32_to_cpu(msg->hdr.data_len);
+               dout("handle_reply result %d bytes %d\n", req->r_result,
+                    bytes);
+               if (req->r_result == 0)
+                       req->r_result = bytes;
+
+               /* in case this is a write and we need to replay, */
+               req->r_reassert_version = rhead->reassert_version;
+
+               req->r_got_reply = 1;
+       } else if ((flags & CEPH_OSD_FLAG_ONDISK) == 0) {
+               dout("handle_reply tid %llu dup ack\n", tid);
+               mutex_unlock(&osdc->request_mutex);
+               goto done;
+       }
+
+       dout("handle_reply tid %llu flags %d\n", tid, flags);
+
+       /* either this is a read, or we got the safe response */
+       if ((flags & CEPH_OSD_FLAG_ONDISK) ||
+           ((flags & CEPH_OSD_FLAG_WRITE) == 0))
+               __unregister_request(osdc, req);
+
+       mutex_unlock(&osdc->request_mutex);
+
+       if (req->r_callback)
+               req->r_callback(req, msg);
+       else
+               complete(&req->r_completion);
+
+       if (flags & CEPH_OSD_FLAG_ONDISK) {
+               if (req->r_safe_callback)
+                       req->r_safe_callback(req, msg);
+               complete(&req->r_safe_completion);  /* fsync waiter */
+       }
+
+done:
+       ceph_osdc_put_request(req);
+       return;
+
+bad:
+       pr_err("corrupt osd_op_reply got %d %d expected %d\n",
+              (int)msg->front.iov_len, le32_to_cpu(msg->hdr.front_len),
+              (int)sizeof(*rhead));
+       ceph_msg_dump(msg);
+}
+
+
+static int __kick_requests(struct ceph_osd_client *osdc,
+                         struct ceph_osd *kickosd)
+{
+       struct ceph_osd_request *req;
+       struct rb_node *p, *n;
+       int needmap = 0;
+       int err;
+
+       dout("kick_requests osd%d\n", kickosd ? kickosd->o_osd : -1);
+       if (kickosd) {
+               __reset_osd(osdc, kickosd);
+       } else {
+               for (p = rb_first(&osdc->osds); p; p = n) {
+                       struct ceph_osd *osd =
+                               rb_entry(p, struct ceph_osd, o_node);
+
+                       n = rb_next(p);
+                       if (!ceph_osd_is_up(osdc->osdmap, osd->o_osd) ||
+                           memcmp(&osd->o_con.peer_addr,
+                                  ceph_osd_addr(osdc->osdmap,
+                                                osd->o_osd),
+                                  sizeof(struct ceph_entity_addr)) != 0)
+                               __reset_osd(osdc, osd);
+               }
+       }
+
+       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+               req = rb_entry(p, struct ceph_osd_request, r_node);
+
+               if (req->r_resend) {
+                       dout(" r_resend set on tid %llu\n", req->r_tid);
+                       __cancel_request(req);
+                       goto kick;
+               }
+               if (req->r_osd && kickosd == req->r_osd) {
+                       __cancel_request(req);
+                       goto kick;
+               }
+
+               err = __map_osds(osdc, req);
+               if (err == 0)
+                       continue;  /* no change */
+               if (err < 0) {
+                       /*
+                        * FIXME: really, we should set the request
+                        * error and fail if this isn't a 'nofail'
+                        * request, but that's a fair bit more
+                        * complicated to do.  So retry!
+                        */
+                       dout(" setting r_resend on %llu\n", req->r_tid);
+                       req->r_resend = true;
+                       continue;
+               }
+               if (req->r_osd == NULL) {
+                       dout("tid %llu maps to no valid osd\n", req->r_tid);
+                       needmap++;  /* request a newer map */
+                       continue;
+               }
+
+kick:
+               dout("kicking %p tid %llu osd%d\n", req, req->r_tid,
+                    req->r_osd->o_osd);
+               req->r_flags |= CEPH_OSD_FLAG_RETRY;
+               err = __send_request(osdc, req);
+               if (err) {
+                       dout(" setting r_resend on %llu\n", req->r_tid);
+                       req->r_resend = true;
+               }
+       }
+
+       return needmap;
+}
+
+/*
+ * Resubmit osd requests whose osd or osd address has changed.  Request
+ * a new osd map if osds are down, or we are otherwise unable to determine
+ * how to direct a request.
+ *
+ * Close connections to down osds.
+ *
+ * If @who is specified, resubmit requests for that specific osd.
+ *
+ * Caller should hold map_sem for read and request_mutex.
+ */
+static void kick_requests(struct ceph_osd_client *osdc,
+                         struct ceph_osd *kickosd)
+{
+       int needmap;
+
+       mutex_lock(&osdc->request_mutex);
+       needmap = __kick_requests(osdc, kickosd);
+       mutex_unlock(&osdc->request_mutex);
+
+       if (needmap) {
+               dout("%d requests for down osds, need new map\n", needmap);
+               ceph_monc_request_next_osdmap(&osdc->client->monc);
+       }
+
+}
+/*
+ * Process updated osd map.
+ *
+ * The message contains any number of incremental and full maps, normally
+ * indicating some sort of topology change in the cluster.  Kick requests
+ * off to different OSDs as needed.
+ */
+void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
+{
+       void *p, *end, *next;
+       u32 nr_maps, maplen;
+       u32 epoch;
+       struct ceph_osdmap *newmap = NULL, *oldmap;
+       int err;
+       struct ceph_fsid fsid;
+
+       dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0);
+       p = msg->front.iov_base;
+       end = p + msg->front.iov_len;
+
+       /* verify fsid */
+       ceph_decode_need(&p, end, sizeof(fsid), bad);
+       ceph_decode_copy(&p, &fsid, sizeof(fsid));
+       if (ceph_check_fsid(osdc->client, &fsid) < 0)
+               return;
+
+       down_write(&osdc->map_sem);
+
+       /* incremental maps */
+       ceph_decode_32_safe(&p, end, nr_maps, bad);
+       dout(" %d inc maps\n", nr_maps);
+       while (nr_maps > 0) {
+               ceph_decode_need(&p, end, 2*sizeof(u32), bad);
+               epoch = ceph_decode_32(&p);
+               maplen = ceph_decode_32(&p);
+               ceph_decode_need(&p, end, maplen, bad);
+               next = p + maplen;
+               if (osdc->osdmap && osdc->osdmap->epoch+1 == epoch) {
+                       dout("applying incremental map %u len %d\n",
+                            epoch, maplen);
+                       newmap = osdmap_apply_incremental(&p, next,
+                                                         osdc->osdmap,
+                                                         osdc->client->msgr);
+                       if (IS_ERR(newmap)) {
+                               err = PTR_ERR(newmap);
+                               goto bad;
+                       }
+                       BUG_ON(!newmap);
+                       if (newmap != osdc->osdmap) {
+                               ceph_osdmap_destroy(osdc->osdmap);
+                               osdc->osdmap = newmap;
+                       }
+               } else {
+                       dout("ignoring incremental map %u len %d\n",
+                            epoch, maplen);
+               }
+               p = next;
+               nr_maps--;
+       }
+       if (newmap)
+               goto done;
+
+       /* full maps */
+       ceph_decode_32_safe(&p, end, nr_maps, bad);
+       dout(" %d full maps\n", nr_maps);
+       while (nr_maps) {
+               ceph_decode_need(&p, end, 2*sizeof(u32), bad);
+               epoch = ceph_decode_32(&p);
+               maplen = ceph_decode_32(&p);
+               ceph_decode_need(&p, end, maplen, bad);
+               if (nr_maps > 1) {
+                       dout("skipping non-latest full map %u len %d\n",
+                            epoch, maplen);
+               } else if (osdc->osdmap && osdc->osdmap->epoch >= epoch) {
+                       dout("skipping full map %u len %d, "
+                            "older than our %u\n", epoch, maplen,
+                            osdc->osdmap->epoch);
+               } else {
+                       dout("taking full map %u len %d\n", epoch, maplen);
+                       newmap = osdmap_decode(&p, p+maplen);
+                       if (IS_ERR(newmap)) {
+                               err = PTR_ERR(newmap);
+                               goto bad;
+                       }
+                       BUG_ON(!newmap);
+                       oldmap = osdc->osdmap;
+                       osdc->osdmap = newmap;
+                       if (oldmap)
+                               ceph_osdmap_destroy(oldmap);
+               }
+               p += maplen;
+               nr_maps--;
+       }
+
+done:
+       downgrade_write(&osdc->map_sem);
+       ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
+       if (newmap)
+               kick_requests(osdc, NULL);
+       up_read(&osdc->map_sem);
+       return;
+
+bad:
+       pr_err("osdc handle_map corrupt msg\n");
+       ceph_msg_dump(msg);
+       up_write(&osdc->map_sem);
+       return;
+}
+
+
+/*
+ * A read request prepares specific pages that data is to be read into.
+ * When a message is being read off the wire, we call prepare_pages to
+ * find those pages.
+ *  0 = success, -1 failure.
+ */
+static int __prepare_pages(struct ceph_connection *con,
+                        struct ceph_msg_header *hdr,
+                        struct ceph_osd_request *req,
+                        u64 tid,
+                        struct ceph_msg *m)
+{
+       struct ceph_osd *osd = con->private;
+       struct ceph_osd_client *osdc;
+       int ret = -1;
+       int data_len = le32_to_cpu(hdr->data_len);
+       unsigned data_off = le16_to_cpu(hdr->data_off);
+
+       int want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
+
+       if (!osd)
+               return -1;
+
+       osdc = osd->o_osdc;
+
+       dout("__prepare_pages on msg %p tid %llu, has %d pages, want %d\n", m,
+            tid, req->r_num_pages, want);
+       if (unlikely(req->r_num_pages < want))
+               goto out;
+       m->pages = req->r_pages;
+       m->nr_pages = req->r_num_pages;
+       ret = 0; /* success */
+out:
+       BUG_ON(ret < 0 || m->nr_pages < want);
+
+       return ret;
+}
+
+/*
+ * Register request, send initial attempt.
+ */
+int ceph_osdc_start_request(struct ceph_osd_client *osdc,
+                           struct ceph_osd_request *req,
+                           bool nofail)
+{
+       int rc = 0;
+
+       req->r_request->pages = req->r_pages;
+       req->r_request->nr_pages = req->r_num_pages;
+
+       register_request(osdc, req);
+
+       down_read(&osdc->map_sem);
+       mutex_lock(&osdc->request_mutex);
+       /*
+        * a racing kick_requests() may have sent the message for us
+        * while we dropped request_mutex above, so only send now if
+        * the request still han't been touched yet.
+        */
+       if (req->r_sent == 0) {
+               rc = __send_request(osdc, req);
+               if (rc) {
+                       if (nofail) {
+                               dout("osdc_start_request failed send, "
+                                    " marking %lld\n", req->r_tid);
+                               req->r_resend = true;
+                               rc = 0;
+                       } else {
+                               __unregister_request(osdc, req);
+                       }
+               }
+       }
+       mutex_unlock(&osdc->request_mutex);
+       up_read(&osdc->map_sem);
+       return rc;
+}
+
+/*
+ * wait for a request to complete
+ */
+int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
+                          struct ceph_osd_request *req)
+{
+       int rc;
+
+       rc = wait_for_completion_interruptible(&req->r_completion);
+       if (rc < 0) {
+               mutex_lock(&osdc->request_mutex);
+               __cancel_request(req);
+               __unregister_request(osdc, req);
+               mutex_unlock(&osdc->request_mutex);
+               dout("wait_request tid %llu canceled/timed out\n", req->r_tid);
+               return rc;
+       }
+
+       dout("wait_request tid %llu result %d\n", req->r_tid, req->r_result);
+       return req->r_result;
+}
+
+/*
+ * sync - wait for all in-flight requests to flush.  avoid starvation.
+ */
+void ceph_osdc_sync(struct ceph_osd_client *osdc)
+{
+       struct ceph_osd_request *req;
+       u64 last_tid, next_tid = 0;
+
+       mutex_lock(&osdc->request_mutex);
+       last_tid = osdc->last_tid;
+       while (1) {
+               req = __lookup_request_ge(osdc, next_tid);
+               if (!req)
+                       break;
+               if (req->r_tid > last_tid)
+                       break;
+
+               next_tid = req->r_tid + 1;
+               if ((req->r_flags & CEPH_OSD_FLAG_WRITE) == 0)
+                       continue;
+
+               ceph_osdc_get_request(req);
+               mutex_unlock(&osdc->request_mutex);
+               dout("sync waiting on tid %llu (last is %llu)\n",
+                    req->r_tid, last_tid);
+               wait_for_completion(&req->r_safe_completion);
+               mutex_lock(&osdc->request_mutex);
+               ceph_osdc_put_request(req);
+       }
+       mutex_unlock(&osdc->request_mutex);
+       dout("sync done (thru tid %llu)\n", last_tid);
+}
+
+/*
+ * init, shutdown
+ */
+int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
+{
+       int err;
+
+       dout("init\n");
+       osdc->client = client;
+       osdc->osdmap = NULL;
+       init_rwsem(&osdc->map_sem);
+       init_completion(&osdc->map_waiters);
+       osdc->last_requested_map = 0;
+       mutex_init(&osdc->request_mutex);
+       osdc->last_tid = 0;
+       osdc->osds = RB_ROOT;
+       INIT_LIST_HEAD(&osdc->osd_lru);
+       osdc->requests = RB_ROOT;
+       INIT_LIST_HEAD(&osdc->req_lru);
+       osdc->num_requests = 0;
+       INIT_DELAYED_WORK(&osdc->timeout_work, handle_timeout);
+       INIT_DELAYED_WORK(&osdc->osds_timeout_work, handle_osds_timeout);
+
+       schedule_delayed_work(&osdc->osds_timeout_work,
+          round_jiffies_relative(osdc->client->mount_args->osd_idle_ttl * HZ));
+
+       err = -ENOMEM;
+       osdc->req_mempool = mempool_create_kmalloc_pool(10,
+                                       sizeof(struct ceph_osd_request));
+       if (!osdc->req_mempool)
+               goto out;
+
+       err = ceph_msgpool_init(&osdc->msgpool_op, OSD_OP_FRONT_LEN, 10, true);
+       if (err < 0)
+               goto out_mempool;
+       err = ceph_msgpool_init(&osdc->msgpool_op_reply,
+                               OSD_OPREPLY_FRONT_LEN, 10, true);
+       if (err < 0)
+               goto out_msgpool;
+       return 0;
+
+out_msgpool:
+       ceph_msgpool_destroy(&osdc->msgpool_op);
+out_mempool:
+       mempool_destroy(osdc->req_mempool);
+out:
+       return err;
+}
+
+void ceph_osdc_stop(struct ceph_osd_client *osdc)
+{
+       cancel_delayed_work_sync(&osdc->timeout_work);
+       cancel_delayed_work_sync(&osdc->osds_timeout_work);
+       if (osdc->osdmap) {
+               ceph_osdmap_destroy(osdc->osdmap);
+               osdc->osdmap = NULL;
+       }
+       remove_old_osds(osdc, 1);
+       mempool_destroy(osdc->req_mempool);
+       ceph_msgpool_destroy(&osdc->msgpool_op);
+       ceph_msgpool_destroy(&osdc->msgpool_op_reply);
+}
+
+/*
+ * Read some contiguous pages.  If we cross a stripe boundary, shorten
+ * *plen.  Return number of bytes read, or error.
+ */
+int ceph_osdc_readpages(struct ceph_osd_client *osdc,
+                       struct ceph_vino vino, struct ceph_file_layout *layout,
+                       u64 off, u64 *plen,
+                       u32 truncate_seq, u64 truncate_size,
+                       struct page **pages, int num_pages)
+{
+       struct ceph_osd_request *req;
+       int rc = 0;
+
+       dout("readpages on ino %llx.%llx on %llu~%llu\n", vino.ino,
+            vino.snap, off, *plen);
+       req = ceph_osdc_new_request(osdc, layout, vino, off, plen,
+                                   CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
+                                   NULL, 0, truncate_seq, truncate_size, NULL,
+                                   false, 1);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       /* it may be a short read due to an object boundary */
+       req->r_pages = pages;
+       num_pages = calc_pages_for(off, *plen);
+       req->r_num_pages = num_pages;
+
+       dout("readpages  final extent is %llu~%llu (%d pages)\n",
+            off, *plen, req->r_num_pages);
+
+       rc = ceph_osdc_start_request(osdc, req, false);
+       if (!rc)
+               rc = ceph_osdc_wait_request(osdc, req);
+
+       ceph_osdc_put_request(req);
+       dout("readpages result %d\n", rc);
+       return rc;
+}
+
+/*
+ * do a synchronous write on N pages
+ */
+int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
+                        struct ceph_file_layout *layout,
+                        struct ceph_snap_context *snapc,
+                        u64 off, u64 len,
+                        u32 truncate_seq, u64 truncate_size,
+                        struct timespec *mtime,
+                        struct page **pages, int num_pages,
+                        int flags, int do_sync, bool nofail)
+{
+       struct ceph_osd_request *req;
+       int rc = 0;
+
+       BUG_ON(vino.snap != CEPH_NOSNAP);
+       req = ceph_osdc_new_request(osdc, layout, vino, off, &len,
+                                   CEPH_OSD_OP_WRITE,
+                                   flags | CEPH_OSD_FLAG_ONDISK |
+                                           CEPH_OSD_FLAG_WRITE,
+                                   snapc, do_sync,
+                                   truncate_seq, truncate_size, mtime,
+                                   nofail, 1);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       /* it may be a short write due to an object boundary */
+       req->r_pages = pages;
+       req->r_num_pages = calc_pages_for(off, len);
+       dout("writepages %llu~%llu (%d pages)\n", off, len,
+            req->r_num_pages);
+
+       rc = ceph_osdc_start_request(osdc, req, nofail);
+       if (!rc)
+               rc = ceph_osdc_wait_request(osdc, req);
+
+       ceph_osdc_put_request(req);
+       if (rc == 0)
+               rc = len;
+       dout("writepages result %d\n", rc);
+       return rc;
+}
+
+/*
+ * handle incoming message
+ */
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_osd *osd = con->private;
+       struct ceph_osd_client *osdc;
+       int type = le16_to_cpu(msg->hdr.type);
+
+       if (!osd)
+               return;
+       osdc = osd->o_osdc;
+
+       switch (type) {
+       case CEPH_MSG_OSD_MAP:
+               ceph_osdc_handle_map(osdc, msg);
+               break;
+       case CEPH_MSG_OSD_OPREPLY:
+               handle_reply(osdc, msg, con);
+               break;
+
+       default:
+               pr_err("received unknown message type %d %s\n", type,
+                      ceph_msg_type_name(type));
+       }
+       ceph_msg_put(msg);
+}
+
+/*
+ * lookup and return message for incoming reply
+ */
+static struct ceph_msg *get_reply(struct ceph_connection *con,
+                                 struct ceph_msg_header *hdr,
+                                 int *skip)
+{
+       struct ceph_osd *osd = con->private;
+       struct ceph_osd_client *osdc = osd->o_osdc;
+       struct ceph_msg *m;
+       struct ceph_osd_request *req;
+       int front = le32_to_cpu(hdr->front_len);
+       int data_len = le32_to_cpu(hdr->data_len);
+       u64 tid;
+       int err;
+
+       tid = le64_to_cpu(hdr->tid);
+       mutex_lock(&osdc->request_mutex);
+       req = __lookup_request(osdc, tid);
+       if (!req) {
+               *skip = 1;
+               m = NULL;
+               pr_info("get_reply unknown tid %llu from osd%d\n", tid,
+                       osd->o_osd);
+               goto out;
+       }
+
+       if (req->r_con_filling_msg) {
+               dout("get_reply revoking msg %p from old con %p\n",
+                    req->r_reply, req->r_con_filling_msg);
+               ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply);
+               ceph_con_put(req->r_con_filling_msg);
+       }
+
+       if (front > req->r_reply->front.iov_len) {
+               pr_warning("get_reply front %d > preallocated %d\n",
+                          front, (int)req->r_reply->front.iov_len);
+               m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, 0, 0, NULL);
+               if (IS_ERR(m))
+                       goto out;
+               ceph_msg_put(req->r_reply);
+               req->r_reply = m;
+       }
+       m = ceph_msg_get(req->r_reply);
+
+       if (data_len > 0) {
+               err = __prepare_pages(con, hdr, req, tid, m);
+               if (err < 0) {
+                       *skip = 1;
+                       ceph_msg_put(m);
+                       m = ERR_PTR(err);
+               }
+       }
+       *skip = 0;
+       req->r_con_filling_msg = ceph_con_get(con);
+       dout("get_reply tid %lld %p\n", tid, m);
+
+out:
+       mutex_unlock(&osdc->request_mutex);
+       return m;
+
+}
+
+static struct ceph_msg *alloc_msg(struct ceph_connection *con,
+                                 struct ceph_msg_header *hdr,
+                                 int *skip)
+{
+       struct ceph_osd *osd = con->private;
+       int type = le16_to_cpu(hdr->type);
+       int front = le32_to_cpu(hdr->front_len);
+
+       switch (type) {
+       case CEPH_MSG_OSD_MAP:
+               return ceph_msg_new(type, front, 0, 0, NULL);
+       case CEPH_MSG_OSD_OPREPLY:
+               return get_reply(con, hdr, skip);
+       default:
+               pr_info("alloc_msg unexpected msg type %d from osd%d\n", type,
+                       osd->o_osd);
+               *skip = 1;
+               return NULL;
+       }
+}
+
+/*
+ * Wrappers to refcount containing ceph_osd struct
+ */
+static struct ceph_connection *get_osd_con(struct ceph_connection *con)
+{
+       struct ceph_osd *osd = con->private;
+       if (get_osd(osd))
+               return con;
+       return NULL;
+}
+
+static void put_osd_con(struct ceph_connection *con)
+{
+       struct ceph_osd *osd = con->private;
+       put_osd(osd);
+}
+
+/*
+ * authentication
+ */
+static int get_authorizer(struct ceph_connection *con,
+                         void **buf, int *len, int *proto,
+                         void **reply_buf, int *reply_len, int force_new)
+{
+       struct ceph_osd *o = con->private;
+       struct ceph_osd_client *osdc = o->o_osdc;
+       struct ceph_auth_client *ac = osdc->client->monc.auth;
+       int ret = 0;
+
+       if (force_new && o->o_authorizer) {
+               ac->ops->destroy_authorizer(ac, o->o_authorizer);
+               o->o_authorizer = NULL;
+       }
+       if (o->o_authorizer == NULL) {
+               ret = ac->ops->create_authorizer(
+                       ac, CEPH_ENTITY_TYPE_OSD,
+                       &o->o_authorizer,
+                       &o->o_authorizer_buf,
+                       &o->o_authorizer_buf_len,
+                       &o->o_authorizer_reply_buf,
+                       &o->o_authorizer_reply_buf_len);
+               if (ret)
+               return ret;
+       }
+
+       *proto = ac->protocol;
+       *buf = o->o_authorizer_buf;
+       *len = o->o_authorizer_buf_len;
+       *reply_buf = o->o_authorizer_reply_buf;
+       *reply_len = o->o_authorizer_reply_buf_len;
+       return 0;
+}
+
+
+static int verify_authorizer_reply(struct ceph_connection *con, int len)
+{
+       struct ceph_osd *o = con->private;
+       struct ceph_osd_client *osdc = o->o_osdc;
+       struct ceph_auth_client *ac = osdc->client->monc.auth;
+
+       return ac->ops->verify_authorizer_reply(ac, o->o_authorizer, len);
+}
+
+static int invalidate_authorizer(struct ceph_connection *con)
+{
+       struct ceph_osd *o = con->private;
+       struct ceph_osd_client *osdc = o->o_osdc;
+       struct ceph_auth_client *ac = osdc->client->monc.auth;
+
+       if (ac->ops->invalidate_authorizer)
+               ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_OSD);
+
+       return ceph_monc_validate_auth(&osdc->client->monc);
+}
+
+const static struct ceph_connection_operations osd_con_ops = {
+       .get = get_osd_con,
+       .put = put_osd_con,
+       .dispatch = dispatch,
+       .get_authorizer = get_authorizer,
+       .verify_authorizer_reply = verify_authorizer_reply,
+       .invalidate_authorizer = invalidate_authorizer,
+       .alloc_msg = alloc_msg,
+       .fault = osd_reset,
+};
diff --git a/fs/ceph/osd_client.h b/fs/ceph/osd_client.h
new file mode 100644 (file)
index 0000000..1b1a3ca
--- /dev/null
@@ -0,0 +1,166 @@
+#ifndef _FS_CEPH_OSD_CLIENT_H
+#define _FS_CEPH_OSD_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/mempool.h>
+#include <linux/rbtree.h>
+
+#include "types.h"
+#include "osdmap.h"
+#include "messenger.h"
+
+struct ceph_msg;
+struct ceph_snap_context;
+struct ceph_osd_request;
+struct ceph_osd_client;
+struct ceph_authorizer;
+
+/*
+ * completion callback for async writepages
+ */
+typedef void (*ceph_osdc_callback_t)(struct ceph_osd_request *,
+                                    struct ceph_msg *);
+
+/* a given osd we're communicating with */
+struct ceph_osd {
+       atomic_t o_ref;
+       struct ceph_osd_client *o_osdc;
+       int o_osd;
+       int o_incarnation;
+       struct rb_node o_node;
+       struct ceph_connection o_con;
+       struct list_head o_requests;
+       struct list_head o_osd_lru;
+       struct ceph_authorizer *o_authorizer;
+       void *o_authorizer_buf, *o_authorizer_reply_buf;
+       size_t o_authorizer_buf_len, o_authorizer_reply_buf_len;
+       unsigned long lru_ttl;
+       int o_marked_for_keepalive;
+       struct list_head o_keepalive_item;
+};
+
+/* an in-flight request */
+struct ceph_osd_request {
+       u64             r_tid;              /* unique for this client */
+       struct rb_node  r_node;
+       struct list_head r_req_lru_item;
+       struct list_head r_osd_item;
+       struct ceph_osd *r_osd;
+       struct ceph_pg   r_pgid;
+
+       struct ceph_connection *r_con_filling_msg;
+
+       struct ceph_msg  *r_request, *r_reply;
+       int               r_result;
+       int               r_flags;     /* any additional flags for the osd */
+       u32               r_sent;      /* >0 if r_request is sending/sent */
+       int               r_got_reply;
+
+       struct ceph_osd_client *r_osdc;
+       struct kref       r_kref;
+       bool              r_mempool;
+       struct completion r_completion, r_safe_completion;
+       ceph_osdc_callback_t r_callback, r_safe_callback;
+       struct ceph_eversion r_reassert_version;
+       struct list_head  r_unsafe_item;
+
+       struct inode *r_inode;                /* for use by callbacks */
+       struct writeback_control *r_wbc;      /* ditto */
+
+       char              r_oid[40];          /* object name */
+       int               r_oid_len;
+       unsigned long     r_sent_stamp;
+       bool              r_resend;           /* msg send failed, needs retry */
+
+       struct ceph_file_layout r_file_layout;
+       struct ceph_snap_context *r_snapc;    /* snap context for writes */
+       unsigned          r_num_pages;        /* size of page array (follows) */
+       struct page     **r_pages;            /* pages for data payload */
+       int               r_pages_from_pool;
+       int               r_own_pages;        /* if true, i own page list */
+};
+
+struct ceph_osd_client {
+       struct ceph_client     *client;
+
+       struct ceph_osdmap     *osdmap;       /* current map */
+       struct rw_semaphore    map_sem;
+       struct completion      map_waiters;
+       u64                    last_requested_map;
+
+       struct mutex           request_mutex;
+       struct rb_root         osds;          /* osds */
+       struct list_head       osd_lru;       /* idle osds */
+       u64                    timeout_tid;   /* tid of timeout triggering rq */
+       u64                    last_tid;      /* tid of last request */
+       struct rb_root         requests;      /* pending requests */
+       struct list_head       req_lru;       /* pending requests lru */
+       int                    num_requests;
+       struct delayed_work    timeout_work;
+       struct delayed_work    osds_timeout_work;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry          *debugfs_file;
+#endif
+
+       mempool_t              *req_mempool;
+
+       struct ceph_msgpool     msgpool_op;
+       struct ceph_msgpool     msgpool_op_reply;
+};
+
+extern int ceph_osdc_init(struct ceph_osd_client *osdc,
+                         struct ceph_client *client);
+extern void ceph_osdc_stop(struct ceph_osd_client *osdc);
+
+extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc,
+                                  struct ceph_msg *msg);
+extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
+                                struct ceph_msg *msg);
+
+extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
+                                     struct ceph_file_layout *layout,
+                                     struct ceph_vino vino,
+                                     u64 offset, u64 *len, int op, int flags,
+                                     struct ceph_snap_context *snapc,
+                                     int do_sync, u32 truncate_seq,
+                                     u64 truncate_size,
+                                     struct timespec *mtime,
+                                     bool use_mempool, int num_reply);
+
+static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
+{
+       kref_get(&req->r_kref);
+}
+extern void ceph_osdc_release_request(struct kref *kref);
+static inline void ceph_osdc_put_request(struct ceph_osd_request *req)
+{
+       kref_put(&req->r_kref, ceph_osdc_release_request);
+}
+
+extern int ceph_osdc_start_request(struct ceph_osd_client *osdc,
+                                  struct ceph_osd_request *req,
+                                  bool nofail);
+extern int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
+                                 struct ceph_osd_request *req);
+extern void ceph_osdc_sync(struct ceph_osd_client *osdc);
+
+extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
+                              struct ceph_vino vino,
+                              struct ceph_file_layout *layout,
+                              u64 off, u64 *plen,
+                              u32 truncate_seq, u64 truncate_size,
+                              struct page **pages, int nr_pages);
+
+extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
+                               struct ceph_vino vino,
+                               struct ceph_file_layout *layout,
+                               struct ceph_snap_context *sc,
+                               u64 off, u64 len,
+                               u32 truncate_seq, u64 truncate_size,
+                               struct timespec *mtime,
+                               struct page **pages, int nr_pages,
+                               int flags, int do_sync, bool nofail);
+
+#endif
+
diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c
new file mode 100644 (file)
index 0000000..b83f269
--- /dev/null
@@ -0,0 +1,1019 @@
+
+#include <asm/div64.h>
+
+#include "super.h"
+#include "osdmap.h"
+#include "crush/hash.h"
+#include "crush/mapper.h"
+#include "decode.h"
+#include "ceph_debug.h"
+
+char *ceph_osdmap_state_str(char *str, int len, int state)
+{
+       int flag = 0;
+
+       if (!len)
+               goto done;
+
+       *str = '\0';
+       if (state) {
+               if (state & CEPH_OSD_EXISTS) {
+                       snprintf(str, len, "exists");
+                       flag = 1;
+               }
+               if (state & CEPH_OSD_UP) {
+                       snprintf(str, len, "%s%s%s", str, (flag ? ", " : ""),
+                                "up");
+                       flag = 1;
+               }
+       } else {
+               snprintf(str, len, "doesn't exist");
+       }
+done:
+       return str;
+}
+
+/* maps */
+
+static int calc_bits_of(unsigned t)
+{
+       int b = 0;
+       while (t) {
+               t = t >> 1;
+               b++;
+       }
+       return b;
+}
+
+/*
+ * the foo_mask is the smallest value 2^n-1 that is >= foo.
+ */
+static void calc_pg_masks(struct ceph_pg_pool_info *pi)
+{
+       pi->pg_num_mask = (1 << calc_bits_of(le32_to_cpu(pi->v.pg_num)-1)) - 1;
+       pi->pgp_num_mask =
+               (1 << calc_bits_of(le32_to_cpu(pi->v.pgp_num)-1)) - 1;
+       pi->lpg_num_mask =
+               (1 << calc_bits_of(le32_to_cpu(pi->v.lpg_num)-1)) - 1;
+       pi->lpgp_num_mask =
+               (1 << calc_bits_of(le32_to_cpu(pi->v.lpgp_num)-1)) - 1;
+}
+
+/*
+ * decode crush map
+ */
+static int crush_decode_uniform_bucket(void **p, void *end,
+                                      struct crush_bucket_uniform *b)
+{
+       dout("crush_decode_uniform_bucket %p to %p\n", *p, end);
+       ceph_decode_need(p, end, (1+b->h.size) * sizeof(u32), bad);
+       b->item_weight = ceph_decode_32(p);
+       return 0;
+bad:
+       return -EINVAL;
+}
+
+static int crush_decode_list_bucket(void **p, void *end,
+                                   struct crush_bucket_list *b)
+{
+       int j;
+       dout("crush_decode_list_bucket %p to %p\n", *p, end);
+       b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+       if (b->item_weights == NULL)
+               return -ENOMEM;
+       b->sum_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+       if (b->sum_weights == NULL)
+               return -ENOMEM;
+       ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);
+       for (j = 0; j < b->h.size; j++) {
+               b->item_weights[j] = ceph_decode_32(p);
+               b->sum_weights[j] = ceph_decode_32(p);
+       }
+       return 0;
+bad:
+       return -EINVAL;
+}
+
+static int crush_decode_tree_bucket(void **p, void *end,
+                                   struct crush_bucket_tree *b)
+{
+       int j;
+       dout("crush_decode_tree_bucket %p to %p\n", *p, end);
+       ceph_decode_32_safe(p, end, b->num_nodes, bad);
+       b->node_weights = kcalloc(b->num_nodes, sizeof(u32), GFP_NOFS);
+       if (b->node_weights == NULL)
+               return -ENOMEM;
+       ceph_decode_need(p, end, b->num_nodes * sizeof(u32), bad);
+       for (j = 0; j < b->num_nodes; j++)
+               b->node_weights[j] = ceph_decode_32(p);
+       return 0;
+bad:
+       return -EINVAL;
+}
+
+static int crush_decode_straw_bucket(void **p, void *end,
+                                    struct crush_bucket_straw *b)
+{
+       int j;
+       dout("crush_decode_straw_bucket %p to %p\n", *p, end);
+       b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+       if (b->item_weights == NULL)
+               return -ENOMEM;
+       b->straws = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+       if (b->straws == NULL)
+               return -ENOMEM;
+       ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);
+       for (j = 0; j < b->h.size; j++) {
+               b->item_weights[j] = ceph_decode_32(p);
+               b->straws[j] = ceph_decode_32(p);
+       }
+       return 0;
+bad:
+       return -EINVAL;
+}
+
+static struct crush_map *crush_decode(void *pbyval, void *end)
+{
+       struct crush_map *c;
+       int err = -EINVAL;
+       int i, j;
+       void **p = &pbyval;
+       void *start = pbyval;
+       u32 magic;
+
+       dout("crush_decode %p to %p len %d\n", *p, end, (int)(end - *p));
+
+       c = kzalloc(sizeof(*c), GFP_NOFS);
+       if (c == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       ceph_decode_need(p, end, 4*sizeof(u32), bad);
+       magic = ceph_decode_32(p);
+       if (magic != CRUSH_MAGIC) {
+               pr_err("crush_decode magic %x != current %x\n",
+                      (unsigned)magic, (unsigned)CRUSH_MAGIC);
+               goto bad;
+       }
+       c->max_buckets = ceph_decode_32(p);
+       c->max_rules = ceph_decode_32(p);
+       c->max_devices = ceph_decode_32(p);
+
+       c->device_parents = kcalloc(c->max_devices, sizeof(u32), GFP_NOFS);
+       if (c->device_parents == NULL)
+               goto badmem;
+       c->bucket_parents = kcalloc(c->max_buckets, sizeof(u32), GFP_NOFS);
+       if (c->bucket_parents == NULL)
+               goto badmem;
+
+       c->buckets = kcalloc(c->max_buckets, sizeof(*c->buckets), GFP_NOFS);
+       if (c->buckets == NULL)
+               goto badmem;
+       c->rules = kcalloc(c->max_rules, sizeof(*c->rules), GFP_NOFS);
+       if (c->rules == NULL)
+               goto badmem;
+
+       /* buckets */
+       for (i = 0; i < c->max_buckets; i++) {
+               int size = 0;
+               u32 alg;
+               struct crush_bucket *b;
+
+               ceph_decode_32_safe(p, end, alg, bad);
+               if (alg == 0) {
+                       c->buckets[i] = NULL;
+                       continue;
+               }
+               dout("crush_decode bucket %d off %x %p to %p\n",
+                    i, (int)(*p-start), *p, end);
+
+               switch (alg) {
+               case CRUSH_BUCKET_UNIFORM:
+                       size = sizeof(struct crush_bucket_uniform);
+                       break;
+               case CRUSH_BUCKET_LIST:
+                       size = sizeof(struct crush_bucket_list);
+                       break;
+               case CRUSH_BUCKET_TREE:
+                       size = sizeof(struct crush_bucket_tree);
+                       break;
+               case CRUSH_BUCKET_STRAW:
+                       size = sizeof(struct crush_bucket_straw);
+                       break;
+               default:
+                       err = -EINVAL;
+                       goto bad;
+               }
+               BUG_ON(size == 0);
+               b = c->buckets[i] = kzalloc(size, GFP_NOFS);
+               if (b == NULL)
+                       goto badmem;
+
+               ceph_decode_need(p, end, 4*sizeof(u32), bad);
+               b->id = ceph_decode_32(p);
+               b->type = ceph_decode_16(p);
+               b->alg = ceph_decode_8(p);
+               b->hash = ceph_decode_8(p);
+               b->weight = ceph_decode_32(p);
+               b->size = ceph_decode_32(p);
+
+               dout("crush_decode bucket size %d off %x %p to %p\n",
+                    b->size, (int)(*p-start), *p, end);
+
+               b->items = kcalloc(b->size, sizeof(__s32), GFP_NOFS);
+               if (b->items == NULL)
+                       goto badmem;
+               b->perm = kcalloc(b->size, sizeof(u32), GFP_NOFS);
+               if (b->perm == NULL)
+                       goto badmem;
+               b->perm_n = 0;
+
+               ceph_decode_need(p, end, b->size*sizeof(u32), bad);
+               for (j = 0; j < b->size; j++)
+                       b->items[j] = ceph_decode_32(p);
+
+               switch (b->alg) {
+               case CRUSH_BUCKET_UNIFORM:
+                       err = crush_decode_uniform_bucket(p, end,
+                                 (struct crush_bucket_uniform *)b);
+                       if (err < 0)
+                               goto bad;
+                       break;
+               case CRUSH_BUCKET_LIST:
+                       err = crush_decode_list_bucket(p, end,
+                              (struct crush_bucket_list *)b);
+                       if (err < 0)
+                               goto bad;
+                       break;
+               case CRUSH_BUCKET_TREE:
+                       err = crush_decode_tree_bucket(p, end,
+                               (struct crush_bucket_tree *)b);
+                       if (err < 0)
+                               goto bad;
+                       break;
+               case CRUSH_BUCKET_STRAW:
+                       err = crush_decode_straw_bucket(p, end,
+                               (struct crush_bucket_straw *)b);
+                       if (err < 0)
+                               goto bad;
+                       break;
+               }
+       }
+
+       /* rules */
+       dout("rule vec is %p\n", c->rules);
+       for (i = 0; i < c->max_rules; i++) {
+               u32 yes;
+               struct crush_rule *r;
+
+               ceph_decode_32_safe(p, end, yes, bad);
+               if (!yes) {
+                       dout("crush_decode NO rule %d off %x %p to %p\n",
+                            i, (int)(*p-start), *p, end);
+                       c->rules[i] = NULL;
+                       continue;
+               }
+
+               dout("crush_decode rule %d off %x %p to %p\n",
+                    i, (int)(*p-start), *p, end);
+
+               /* len */
+               ceph_decode_32_safe(p, end, yes, bad);
+#if BITS_PER_LONG == 32
+               err = -EINVAL;
+               if (yes > ULONG_MAX / sizeof(struct crush_rule_step))
+                       goto bad;
+#endif
+               r = c->rules[i] = kmalloc(sizeof(*r) +
+                                         yes*sizeof(struct crush_rule_step),
+                                         GFP_NOFS);
+               if (r == NULL)
+                       goto badmem;
+               dout(" rule %d is at %p\n", i, r);
+               r->len = yes;
+               ceph_decode_copy_safe(p, end, &r->mask, 4, bad); /* 4 u8's */
+               ceph_decode_need(p, end, r->len*3*sizeof(u32), bad);
+               for (j = 0; j < r->len; j++) {
+                       r->steps[j].op = ceph_decode_32(p);
+                       r->steps[j].arg1 = ceph_decode_32(p);
+                       r->steps[j].arg2 = ceph_decode_32(p);
+               }
+       }
+
+       /* ignore trailing name maps. */
+
+       dout("crush_decode success\n");
+       return c;
+
+badmem:
+       err = -ENOMEM;
+bad:
+       dout("crush_decode fail %d\n", err);
+       crush_destroy(c);
+       return ERR_PTR(err);
+}
+
+
+/*
+ * osd map
+ */
+void ceph_osdmap_destroy(struct ceph_osdmap *map)
+{
+       dout("osdmap_destroy %p\n", map);
+       if (map->crush)
+               crush_destroy(map->crush);
+       while (!RB_EMPTY_ROOT(&map->pg_temp)) {
+               struct ceph_pg_mapping *pg =
+                       rb_entry(rb_first(&map->pg_temp),
+                                struct ceph_pg_mapping, node);
+               rb_erase(&pg->node, &map->pg_temp);
+               kfree(pg);
+       }
+       while (!RB_EMPTY_ROOT(&map->pg_pools)) {
+               struct ceph_pg_pool_info *pi =
+                       rb_entry(rb_first(&map->pg_pools),
+                                struct ceph_pg_pool_info, node);
+               rb_erase(&pi->node, &map->pg_pools);
+               kfree(pi);
+       }
+       kfree(map->osd_state);
+       kfree(map->osd_weight);
+       kfree(map->osd_addr);
+       kfree(map);
+}
+
+/*
+ * adjust max osd value.  reallocate arrays.
+ */
+static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
+{
+       u8 *state;
+       struct ceph_entity_addr *addr;
+       u32 *weight;
+
+       state = kcalloc(max, sizeof(*state), GFP_NOFS);
+       addr = kcalloc(max, sizeof(*addr), GFP_NOFS);
+       weight = kcalloc(max, sizeof(*weight), GFP_NOFS);
+       if (state == NULL || addr == NULL || weight == NULL) {
+               kfree(state);
+               kfree(addr);
+               kfree(weight);
+               return -ENOMEM;
+       }
+
+       /* copy old? */
+       if (map->osd_state) {
+               memcpy(state, map->osd_state, map->max_osd*sizeof(*state));
+               memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr));
+               memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight));
+               kfree(map->osd_state);
+               kfree(map->osd_addr);
+               kfree(map->osd_weight);
+       }
+
+       map->osd_state = state;
+       map->osd_weight = weight;
+       map->osd_addr = addr;
+       map->max_osd = max;
+       return 0;
+}
+
+/*
+ * rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid
+ * to a set of osds)
+ */
+static int pgid_cmp(struct ceph_pg l, struct ceph_pg r)
+{
+       u64 a = *(u64 *)&l;
+       u64 b = *(u64 *)&r;
+
+       if (a < b)
+               return -1;
+       if (a > b)
+               return 1;
+       return 0;
+}
+
+static int __insert_pg_mapping(struct ceph_pg_mapping *new,
+                              struct rb_root *root)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_pg_mapping *pg = NULL;
+       int c;
+
+       while (*p) {
+               parent = *p;
+               pg = rb_entry(parent, struct ceph_pg_mapping, node);
+               c = pgid_cmp(new->pgid, pg->pgid);
+               if (c < 0)
+                       p = &(*p)->rb_left;
+               else if (c > 0)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(&new->node, parent, p);
+       rb_insert_color(&new->node, root);
+       return 0;
+}
+
+static struct ceph_pg_mapping *__lookup_pg_mapping(struct rb_root *root,
+                                                  struct ceph_pg pgid)
+{
+       struct rb_node *n = root->rb_node;
+       struct ceph_pg_mapping *pg;
+       int c;
+
+       while (n) {
+               pg = rb_entry(n, struct ceph_pg_mapping, node);
+               c = pgid_cmp(pgid, pg->pgid);
+               if (c < 0)
+                       n = n->rb_left;
+               else if (c > 0)
+                       n = n->rb_right;
+               else
+                       return pg;
+       }
+       return NULL;
+}
+
+/*
+ * rbtree of pg pool info
+ */
+static int __insert_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *new)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_pg_pool_info *pi = NULL;
+
+       while (*p) {
+               parent = *p;
+               pi = rb_entry(parent, struct ceph_pg_pool_info, node);
+               if (new->id < pi->id)
+                       p = &(*p)->rb_left;
+               else if (new->id > pi->id)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(&new->node, parent, p);
+       rb_insert_color(&new->node, root);
+       return 0;
+}
+
+static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id)
+{
+       struct ceph_pg_pool_info *pi;
+       struct rb_node *n = root->rb_node;
+
+       while (n) {
+               pi = rb_entry(n, struct ceph_pg_pool_info, node);
+               if (id < pi->id)
+                       n = n->rb_left;
+               else if (id > pi->id)
+                       n = n->rb_right;
+               else
+                       return pi;
+       }
+       return NULL;
+}
+
+/*
+ * decode a full map.
+ */
+struct ceph_osdmap *osdmap_decode(void **p, void *end)
+{
+       struct ceph_osdmap *map;
+       u16 version;
+       u32 len, max, i;
+       u8 ev;
+       int err = -EINVAL;
+       void *start = *p;
+       struct ceph_pg_pool_info *pi;
+
+       dout("osdmap_decode %p to %p len %d\n", *p, end, (int)(end - *p));
+
+       map = kzalloc(sizeof(*map), GFP_NOFS);
+       if (map == NULL)
+               return ERR_PTR(-ENOMEM);
+       map->pg_temp = RB_ROOT;
+
+       ceph_decode_16_safe(p, end, version, bad);
+       if (version > CEPH_OSDMAP_VERSION) {
+               pr_warning("got unknown v %d > %d of osdmap\n", version,
+                          CEPH_OSDMAP_VERSION);
+               goto bad;
+       }
+
+       ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), bad);
+       ceph_decode_copy(p, &map->fsid, sizeof(map->fsid));
+       map->epoch = ceph_decode_32(p);
+       ceph_decode_copy(p, &map->created, sizeof(map->created));
+       ceph_decode_copy(p, &map->modified, sizeof(map->modified));
+
+       ceph_decode_32_safe(p, end, max, bad);
+       while (max--) {
+               ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad);
+               pi = kmalloc(sizeof(*pi), GFP_NOFS);
+               if (!pi)
+                       goto bad;
+               pi->id = ceph_decode_32(p);
+               ev = ceph_decode_8(p); /* encoding version */
+               if (ev > CEPH_PG_POOL_VERSION) {
+                       pr_warning("got unknown v %d > %d of ceph_pg_pool\n",
+                                  ev, CEPH_PG_POOL_VERSION);
+                       goto bad;
+               }
+               ceph_decode_copy(p, &pi->v, sizeof(pi->v));
+               __insert_pg_pool(&map->pg_pools, pi);
+               calc_pg_masks(pi);
+               *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64);
+               *p += le32_to_cpu(pi->v.num_removed_snap_intervals)
+                       * sizeof(u64) * 2;
+       }
+       ceph_decode_32_safe(p, end, map->pool_max, bad);
+
+       ceph_decode_32_safe(p, end, map->flags, bad);
+
+       max = ceph_decode_32(p);
+
+       /* (re)alloc osd arrays */
+       err = osdmap_set_max_osd(map, max);
+       if (err < 0)
+               goto bad;
+       dout("osdmap_decode max_osd = %d\n", map->max_osd);
+
+       /* osds */
+       err = -EINVAL;
+       ceph_decode_need(p, end, 3*sizeof(u32) +
+                        map->max_osd*(1 + sizeof(*map->osd_weight) +
+                                      sizeof(*map->osd_addr)), bad);
+       *p += 4; /* skip length field (should match max) */
+       ceph_decode_copy(p, map->osd_state, map->max_osd);
+
+       *p += 4; /* skip length field (should match max) */
+       for (i = 0; i < map->max_osd; i++)
+               map->osd_weight[i] = ceph_decode_32(p);
+
+       *p += 4; /* skip length field (should match max) */
+       ceph_decode_copy(p, map->osd_addr, map->max_osd*sizeof(*map->osd_addr));
+       for (i = 0; i < map->max_osd; i++)
+               ceph_decode_addr(&map->osd_addr[i]);
+
+       /* pg_temp */
+       ceph_decode_32_safe(p, end, len, bad);
+       for (i = 0; i < len; i++) {
+               int n, j;
+               struct ceph_pg pgid;
+               struct ceph_pg_mapping *pg;
+
+               ceph_decode_need(p, end, sizeof(u32) + sizeof(u64), bad);
+               ceph_decode_copy(p, &pgid, sizeof(pgid));
+               n = ceph_decode_32(p);
+               ceph_decode_need(p, end, n * sizeof(u32), bad);
+               err = -ENOMEM;
+               pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
+               if (!pg)
+                       goto bad;
+               pg->pgid = pgid;
+               pg->len = n;
+               for (j = 0; j < n; j++)
+                       pg->osds[j] = ceph_decode_32(p);
+
+               err = __insert_pg_mapping(pg, &map->pg_temp);
+               if (err)
+                       goto bad;
+               dout(" added pg_temp %llx len %d\n", *(u64 *)&pgid, len);
+       }
+
+       /* crush */
+       ceph_decode_32_safe(p, end, len, bad);
+       dout("osdmap_decode crush len %d from off 0x%x\n", len,
+            (int)(*p - start));
+       ceph_decode_need(p, end, len, bad);
+       map->crush = crush_decode(*p, end);
+       *p += len;
+       if (IS_ERR(map->crush)) {
+               err = PTR_ERR(map->crush);
+               map->crush = NULL;
+               goto bad;
+       }
+
+       /* ignore the rest of the map */
+       *p = end;
+
+       dout("osdmap_decode done %p %p\n", *p, end);
+       return map;
+
+bad:
+       dout("osdmap_decode fail\n");
+       ceph_osdmap_destroy(map);
+       return ERR_PTR(err);
+}
+
+/*
+ * decode and apply an incremental map update.
+ */
+struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
+                                            struct ceph_osdmap *map,
+                                            struct ceph_messenger *msgr)
+{
+       struct crush_map *newcrush = NULL;
+       struct ceph_fsid fsid;
+       u32 epoch = 0;
+       struct ceph_timespec modified;
+       u32 len, pool;
+       __s32 new_pool_max, new_flags, max;
+       void *start = *p;
+       int err = -EINVAL;
+       u16 version;
+       struct rb_node *rbp;
+
+       ceph_decode_16_safe(p, end, version, bad);
+       if (version > CEPH_OSDMAP_INC_VERSION) {
+               pr_warning("got unknown v %d > %d of inc osdmap\n", version,
+                          CEPH_OSDMAP_INC_VERSION);
+               goto bad;
+       }
+
+       ceph_decode_need(p, end, sizeof(fsid)+sizeof(modified)+2*sizeof(u32),
+                        bad);
+       ceph_decode_copy(p, &fsid, sizeof(fsid));
+       epoch = ceph_decode_32(p);
+       BUG_ON(epoch != map->epoch+1);
+       ceph_decode_copy(p, &modified, sizeof(modified));
+       new_pool_max = ceph_decode_32(p);
+       new_flags = ceph_decode_32(p);
+
+       /* full map? */
+       ceph_decode_32_safe(p, end, len, bad);
+       if (len > 0) {
+               dout("apply_incremental full map len %d, %p to %p\n",
+                    len, *p, end);
+               return osdmap_decode(p, min(*p+len, end));
+       }
+
+       /* new crush? */
+       ceph_decode_32_safe(p, end, len, bad);
+       if (len > 0) {
+               dout("apply_incremental new crush map len %d, %p to %p\n",
+                    len, *p, end);
+               newcrush = crush_decode(*p, min(*p+len, end));
+               if (IS_ERR(newcrush))
+                       return ERR_PTR(PTR_ERR(newcrush));
+       }
+
+       /* new flags? */
+       if (new_flags >= 0)
+               map->flags = new_flags;
+       if (new_pool_max >= 0)
+               map->pool_max = new_pool_max;
+
+       ceph_decode_need(p, end, 5*sizeof(u32), bad);
+
+       /* new max? */
+       max = ceph_decode_32(p);
+       if (max >= 0) {
+               err = osdmap_set_max_osd(map, max);
+               if (err < 0)
+                       goto bad;
+       }
+
+       map->epoch++;
+       map->modified = map->modified;
+       if (newcrush) {
+               if (map->crush)
+                       crush_destroy(map->crush);
+               map->crush = newcrush;
+               newcrush = NULL;
+       }
+
+       /* new_pool */
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               __u8 ev;
+               struct ceph_pg_pool_info *pi;
+
+               ceph_decode_32_safe(p, end, pool, bad);
+               ceph_decode_need(p, end, 1 + sizeof(pi->v), bad);
+               ev = ceph_decode_8(p);  /* encoding version */
+               if (ev > CEPH_PG_POOL_VERSION) {
+                       pr_warning("got unknown v %d > %d of ceph_pg_pool\n",
+                                  ev, CEPH_PG_POOL_VERSION);
+                       goto bad;
+               }
+               pi = __lookup_pg_pool(&map->pg_pools, pool);
+               if (!pi) {
+                       pi = kmalloc(sizeof(*pi), GFP_NOFS);
+                       if (!pi) {
+                               err = -ENOMEM;
+                               goto bad;
+                       }
+                       pi->id = pool;
+                       __insert_pg_pool(&map->pg_pools, pi);
+               }
+               ceph_decode_copy(p, &pi->v, sizeof(pi->v));
+               calc_pg_masks(pi);
+       }
+
+       /* old_pool */
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               struct ceph_pg_pool_info *pi;
+
+               ceph_decode_32_safe(p, end, pool, bad);
+               pi = __lookup_pg_pool(&map->pg_pools, pool);
+               if (pi) {
+                       rb_erase(&pi->node, &map->pg_pools);
+                       kfree(pi);
+               }
+       }
+
+       /* new_up */
+       err = -EINVAL;
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               u32 osd;
+               struct ceph_entity_addr addr;
+               ceph_decode_32_safe(p, end, osd, bad);
+               ceph_decode_copy_safe(p, end, &addr, sizeof(addr), bad);
+               ceph_decode_addr(&addr);
+               pr_info("osd%d up\n", osd);
+               BUG_ON(osd >= map->max_osd);
+               map->osd_state[osd] |= CEPH_OSD_UP;
+               map->osd_addr[osd] = addr;
+       }
+
+       /* new_down */
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               u32 osd;
+               ceph_decode_32_safe(p, end, osd, bad);
+               (*p)++;  /* clean flag */
+               pr_info("osd%d down\n", osd);
+               if (osd < map->max_osd)
+                       map->osd_state[osd] &= ~CEPH_OSD_UP;
+       }
+
+       /* new_weight */
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               u32 osd, off;
+               ceph_decode_need(p, end, sizeof(u32)*2, bad);
+               osd = ceph_decode_32(p);
+               off = ceph_decode_32(p);
+               pr_info("osd%d weight 0x%x %s\n", osd, off,
+                    off == CEPH_OSD_IN ? "(in)" :
+                    (off == CEPH_OSD_OUT ? "(out)" : ""));
+               if (osd < map->max_osd)
+                       map->osd_weight[osd] = off;
+       }
+
+       /* new_pg_temp */
+       rbp = rb_first(&map->pg_temp);
+       ceph_decode_32_safe(p, end, len, bad);
+       while (len--) {
+               struct ceph_pg_mapping *pg;
+               int j;
+               struct ceph_pg pgid;
+               u32 pglen;
+               ceph_decode_need(p, end, sizeof(u64) + sizeof(u32), bad);
+               ceph_decode_copy(p, &pgid, sizeof(pgid));
+               pglen = ceph_decode_32(p);
+
+               /* remove any? */
+               while (rbp && pgid_cmp(rb_entry(rbp, struct ceph_pg_mapping,
+                                               node)->pgid, pgid) <= 0) {
+                       struct rb_node *cur = rbp;
+                       rbp = rb_next(rbp);
+                       dout(" removed pg_temp %llx\n",
+                            *(u64 *)&rb_entry(cur, struct ceph_pg_mapping,
+                                              node)->pgid);
+                       rb_erase(cur, &map->pg_temp);
+               }
+
+               if (pglen) {
+                       /* insert */
+                       ceph_decode_need(p, end, pglen*sizeof(u32), bad);
+                       pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
+                       if (!pg) {
+                               err = -ENOMEM;
+                               goto bad;
+                       }
+                       pg->pgid = pgid;
+                       pg->len = pglen;
+                       for (j = 0; j < pglen; j++)
+                               pg->osds[j] = ceph_decode_32(p);
+                       err = __insert_pg_mapping(pg, &map->pg_temp);
+                       if (err)
+                               goto bad;
+                       dout(" added pg_temp %llx len %d\n", *(u64 *)&pgid,
+                            pglen);
+               }
+       }
+       while (rbp) {
+               struct rb_node *cur = rbp;
+               rbp = rb_next(rbp);
+               dout(" removed pg_temp %llx\n",
+                    *(u64 *)&rb_entry(cur, struct ceph_pg_mapping,
+                                      node)->pgid);
+               rb_erase(cur, &map->pg_temp);
+       }
+
+       /* ignore the rest */
+       *p = end;
+       return map;
+
+bad:
+       pr_err("corrupt inc osdmap epoch %d off %d (%p of %p-%p)\n",
+              epoch, (int)(*p - start), *p, start, end);
+       print_hex_dump(KERN_DEBUG, "osdmap: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      start, end - start, true);
+       if (newcrush)
+               crush_destroy(newcrush);
+       return ERR_PTR(err);
+}
+
+
+
+
+/*
+ * calculate file layout from given offset, length.
+ * fill in correct oid, logical length, and object extent
+ * offset, length.
+ *
+ * for now, we write only a single su, until we can
+ * pass a stride back to the caller.
+ */
+void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
+                                  u64 off, u64 *plen,
+                                  u64 *ono,
+                                  u64 *oxoff, u64 *oxlen)
+{
+       u32 osize = le32_to_cpu(layout->fl_object_size);
+       u32 su = le32_to_cpu(layout->fl_stripe_unit);
+       u32 sc = le32_to_cpu(layout->fl_stripe_count);
+       u32 bl, stripeno, stripepos, objsetno;
+       u32 su_per_object;
+       u64 t, su_offset;
+
+       dout("mapping %llu~%llu  osize %u fl_su %u\n", off, *plen,
+            osize, su);
+       su_per_object = osize / su;
+       dout("osize %u / su %u = su_per_object %u\n", osize, su,
+            su_per_object);
+
+       BUG_ON((su & ~PAGE_MASK) != 0);
+       /* bl = *off / su; */
+       t = off;
+       do_div(t, su);
+       bl = t;
+       dout("off %llu / su %u = bl %u\n", off, su, bl);
+
+       stripeno = bl / sc;
+       stripepos = bl % sc;
+       objsetno = stripeno / su_per_object;
+
+       *ono = objsetno * sc + stripepos;
+       dout("objset %u * sc %u = ono %u\n", objsetno, sc, (unsigned)*ono);
+
+       /* *oxoff = *off % layout->fl_stripe_unit;  # offset in su */
+       t = off;
+       su_offset = do_div(t, su);
+       *oxoff = su_offset + (stripeno % su_per_object) * su;
+
+       /*
+        * Calculate the length of the extent being written to the selected
+        * object. This is the minimum of the full length requested (plen) or
+        * the remainder of the current stripe being written to.
+        */
+       *oxlen = min_t(u64, *plen, su - su_offset);
+       *plen = *oxlen;
+
+       dout(" obj extent %llu~%llu\n", *oxoff, *oxlen);
+}
+
+/*
+ * calculate an object layout (i.e. pgid) from an oid,
+ * file_layout, and osdmap
+ */
+int ceph_calc_object_layout(struct ceph_object_layout *ol,
+                           const char *oid,
+                           struct ceph_file_layout *fl,
+                           struct ceph_osdmap *osdmap)
+{
+       unsigned num, num_mask;
+       struct ceph_pg pgid;
+       s32 preferred = (s32)le32_to_cpu(fl->fl_pg_preferred);
+       int poolid = le32_to_cpu(fl->fl_pg_pool);
+       struct ceph_pg_pool_info *pool;
+       unsigned ps;
+
+       BUG_ON(!osdmap);
+
+       pool = __lookup_pg_pool(&osdmap->pg_pools, poolid);
+       if (!pool)
+               return -EIO;
+       ps = ceph_str_hash(pool->v.object_hash, oid, strlen(oid));
+       if (preferred >= 0) {
+               ps += preferred;
+               num = le32_to_cpu(pool->v.lpg_num);
+               num_mask = pool->lpg_num_mask;
+       } else {
+               num = le32_to_cpu(pool->v.pg_num);
+               num_mask = pool->pg_num_mask;
+       }
+
+       pgid.ps = cpu_to_le16(ps);
+       pgid.preferred = cpu_to_le16(preferred);
+       pgid.pool = fl->fl_pg_pool;
+       if (preferred >= 0)
+               dout("calc_object_layout '%s' pgid %d.%xp%d\n", oid, poolid, ps,
+                    (int)preferred);
+       else
+               dout("calc_object_layout '%s' pgid %d.%x\n", oid, poolid, ps);
+
+       ol->ol_pgid = pgid;
+       ol->ol_stripe_unit = fl->fl_object_stripe_unit;
+       return 0;
+}
+
+/*
+ * Calculate raw osd vector for the given pgid.  Return pointer to osd
+ * array, or NULL on failure.
+ */
+static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
+                       int *osds, int *num)
+{
+       struct ceph_pg_mapping *pg;
+       struct ceph_pg_pool_info *pool;
+       int ruleno;
+       unsigned poolid, ps, pps;
+       int preferred;
+
+       /* pg_temp? */
+       pg = __lookup_pg_mapping(&osdmap->pg_temp, pgid);
+       if (pg) {
+               *num = pg->len;
+               return pg->osds;
+       }
+
+       /* crush */
+       poolid = le32_to_cpu(pgid.pool);
+       ps = le16_to_cpu(pgid.ps);
+       preferred = (s16)le16_to_cpu(pgid.preferred);
+
+       /* don't forcefeed bad device ids to crush */
+       if (preferred >= osdmap->max_osd ||
+           preferred >= osdmap->crush->max_devices)
+               preferred = -1;
+
+       pool = __lookup_pg_pool(&osdmap->pg_pools, poolid);
+       if (!pool)
+               return NULL;
+       ruleno = crush_find_rule(osdmap->crush, pool->v.crush_ruleset,
+                                pool->v.type, pool->v.size);
+       if (ruleno < 0) {
+               pr_err("no crush rule pool %d type %d size %d\n",
+                      poolid, pool->v.type, pool->v.size);
+               return NULL;
+       }
+
+       if (preferred >= 0)
+               pps = ceph_stable_mod(ps,
+                                     le32_to_cpu(pool->v.lpgp_num),
+                                     pool->lpgp_num_mask);
+       else
+               pps = ceph_stable_mod(ps,
+                                     le32_to_cpu(pool->v.pgp_num),
+                                     pool->pgp_num_mask);
+       pps += poolid;
+       *num = crush_do_rule(osdmap->crush, ruleno, pps, osds,
+                            min_t(int, pool->v.size, *num),
+                            preferred, osdmap->osd_weight);
+       return osds;
+}
+
+/*
+ * Return primary osd for given pgid, or -1 if none.
+ */
+int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid)
+{
+       int rawosds[10], *osds;
+       int i, num = ARRAY_SIZE(rawosds);
+
+       osds = calc_pg_raw(osdmap, pgid, rawosds, &num);
+       if (!osds)
+               return -1;
+
+       /* primary is first up osd */
+       for (i = 0; i < num; i++)
+               if (ceph_osd_is_up(osdmap, osds[i])) {
+                       return osds[i];
+                       break;
+               }
+       return -1;
+}
diff --git a/fs/ceph/osdmap.h b/fs/ceph/osdmap.h
new file mode 100644 (file)
index 0000000..1fb55af
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef _FS_CEPH_OSDMAP_H
+#define _FS_CEPH_OSDMAP_H
+
+#include <linux/rbtree.h>
+#include "types.h"
+#include "ceph_fs.h"
+#include "crush/crush.h"
+
+/*
+ * The osd map describes the current membership of the osd cluster and
+ * specifies the mapping of objects to placement groups and placement
+ * groups to (sets of) osds.  That is, it completely specifies the
+ * (desired) distribution of all data objects in the system at some
+ * point in time.
+ *
+ * Each map version is identified by an epoch, which increases monotonically.
+ *
+ * The map can be updated either via an incremental map (diff) describing
+ * the change between two successive epochs, or as a fully encoded map.
+ */
+struct ceph_pg_pool_info {
+       struct rb_node node;
+       int id;
+       struct ceph_pg_pool v;
+       int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask;
+};
+
+struct ceph_pg_mapping {
+       struct rb_node node;
+       struct ceph_pg pgid;
+       int len;
+       int osds[];
+};
+
+struct ceph_osdmap {
+       struct ceph_fsid fsid;
+       u32 epoch;
+       u32 mkfs_epoch;
+       struct ceph_timespec created, modified;
+
+       u32 flags;         /* CEPH_OSDMAP_* */
+
+       u32 max_osd;       /* size of osd_state, _offload, _addr arrays */
+       u8 *osd_state;     /* CEPH_OSD_* */
+       u32 *osd_weight;   /* 0 = failed, 0x10000 = 100% normal */
+       struct ceph_entity_addr *osd_addr;
+
+       struct rb_root pg_temp;
+       struct rb_root pg_pools;
+       u32 pool_max;
+
+       /* the CRUSH map specifies the mapping of placement groups to
+        * the list of osds that store+replicate them. */
+       struct crush_map *crush;
+};
+
+/*
+ * file layout helpers
+ */
+#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
+#define ceph_file_layout_stripe_count(l) \
+       ((__s32)le32_to_cpu((l).fl_stripe_count))
+#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
+#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
+#define ceph_file_layout_object_su(l) \
+       ((__s32)le32_to_cpu((l).fl_object_stripe_unit))
+#define ceph_file_layout_pg_preferred(l) \
+       ((__s32)le32_to_cpu((l).fl_pg_preferred))
+#define ceph_file_layout_pg_pool(l) \
+       ((__s32)le32_to_cpu((l).fl_pg_pool))
+
+static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
+{
+       return le32_to_cpu(l->fl_stripe_unit) *
+               le32_to_cpu(l->fl_stripe_count);
+}
+
+/* "period" == bytes before i start on a new set of objects */
+static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
+{
+       return le32_to_cpu(l->fl_object_size) *
+               le32_to_cpu(l->fl_stripe_count);
+}
+
+
+static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd)
+{
+       return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP);
+}
+
+static inline bool ceph_osdmap_flag(struct ceph_osdmap *map, int flag)
+{
+       return map && (map->flags & flag);
+}
+
+extern char *ceph_osdmap_state_str(char *str, int len, int state);
+
+static inline struct ceph_entity_addr *ceph_osd_addr(struct ceph_osdmap *map,
+                                                    int osd)
+{
+       if (osd >= map->max_osd)
+               return NULL;
+       return &map->osd_addr[osd];
+}
+
+extern struct ceph_osdmap *osdmap_decode(void **p, void *end);
+extern struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
+                                           struct ceph_osdmap *map,
+                                           struct ceph_messenger *msgr);
+extern void ceph_osdmap_destroy(struct ceph_osdmap *map);
+
+/* calculate mapping of a file extent to an object */
+extern void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
+                                         u64 off, u64 *plen,
+                                         u64 *bno, u64 *oxoff, u64 *oxlen);
+
+/* calculate mapping of object to a placement group */
+extern int ceph_calc_object_layout(struct ceph_object_layout *ol,
+                                  const char *oid,
+                                  struct ceph_file_layout *fl,
+                                  struct ceph_osdmap *osdmap);
+extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
+                               struct ceph_pg pgid);
+
+#endif
diff --git a/fs/ceph/pagelist.c b/fs/ceph/pagelist.c
new file mode 100644 (file)
index 0000000..370e936
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+
+#include "pagelist.h"
+
+int ceph_pagelist_release(struct ceph_pagelist *pl)
+{
+       if (pl->mapped_tail)
+               kunmap(pl->mapped_tail);
+       while (!list_empty(&pl->head)) {
+               struct page *page = list_first_entry(&pl->head, struct page,
+                                                    lru);
+               list_del(&page->lru);
+               __free_page(page);
+       }
+       return 0;
+}
+
+static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
+{
+       struct page *page = alloc_page(GFP_NOFS);
+       if (!page)
+               return -ENOMEM;
+       pl->room += PAGE_SIZE;
+       list_add_tail(&page->lru, &pl->head);
+       if (pl->mapped_tail)
+               kunmap(pl->mapped_tail);
+       pl->mapped_tail = kmap(page);
+       return 0;
+}
+
+int ceph_pagelist_append(struct ceph_pagelist *pl, void *buf, size_t len)
+{
+       while (pl->room < len) {
+               size_t bit = pl->room;
+               int ret;
+
+               memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK),
+                      buf, bit);
+               pl->length += bit;
+               pl->room -= bit;
+               buf += bit;
+               len -= bit;
+               ret = ceph_pagelist_addpage(pl);
+               if (ret)
+                       return ret;
+       }
+
+       memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len);
+       pl->length += len;
+       pl->room -= len;
+       return 0;
+}
diff --git a/fs/ceph/pagelist.h b/fs/ceph/pagelist.h
new file mode 100644 (file)
index 0000000..e8a4187
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __FS_CEPH_PAGELIST_H
+#define __FS_CEPH_PAGELIST_H
+
+#include <linux/list.h>
+
+struct ceph_pagelist {
+       struct list_head head;
+       void *mapped_tail;
+       size_t length;
+       size_t room;
+};
+
+static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
+{
+       INIT_LIST_HEAD(&pl->head);
+       pl->mapped_tail = NULL;
+       pl->length = 0;
+       pl->room = 0;
+}
+extern int ceph_pagelist_release(struct ceph_pagelist *pl);
+
+extern int ceph_pagelist_append(struct ceph_pagelist *pl, void *d, size_t l);
+
+static inline int ceph_pagelist_encode_64(struct ceph_pagelist *pl, u64 v)
+{
+       __le64 ev = cpu_to_le64(v);
+       return ceph_pagelist_append(pl, &ev, sizeof(ev));
+}
+static inline int ceph_pagelist_encode_32(struct ceph_pagelist *pl, u32 v)
+{
+       __le32 ev = cpu_to_le32(v);
+       return ceph_pagelist_append(pl, &ev, sizeof(ev));
+}
+static inline int ceph_pagelist_encode_16(struct ceph_pagelist *pl, u16 v)
+{
+       __le16 ev = cpu_to_le16(v);
+       return ceph_pagelist_append(pl, &ev, sizeof(ev));
+}
+static inline int ceph_pagelist_encode_8(struct ceph_pagelist *pl, u8 v)
+{
+       return ceph_pagelist_append(pl, &v, 1);
+}
+static inline int ceph_pagelist_encode_string(struct ceph_pagelist *pl,
+                                             char *s, size_t len)
+{
+       int ret = ceph_pagelist_encode_32(pl, len);
+       if (ret)
+               return ret;
+       if (len)
+               return ceph_pagelist_append(pl, s, len);
+       return 0;
+}
+
+#endif
diff --git a/fs/ceph/rados.h b/fs/ceph/rados.h
new file mode 100644 (file)
index 0000000..26ac8b8
--- /dev/null
@@ -0,0 +1,374 @@
+#ifndef __RADOS_H
+#define __RADOS_H
+
+/*
+ * Data types for the Ceph distributed object storage layer RADOS
+ * (Reliable Autonomic Distributed Object Store).
+ */
+
+#include "msgr.h"
+
+/*
+ * osdmap encoding versions
+ */
+#define CEPH_OSDMAP_INC_VERSION 4
+#define CEPH_OSDMAP_VERSION     4
+
+/*
+ * fs id
+ */
+struct ceph_fsid {
+       unsigned char fsid[16];
+};
+
+static inline int ceph_fsid_compare(const struct ceph_fsid *a,
+                                   const struct ceph_fsid *b)
+{
+       return memcmp(a, b, sizeof(*a));
+}
+
+/*
+ * ino, object, etc.
+ */
+typedef __le64 ceph_snapid_t;
+#define CEPH_SNAPDIR ((__u64)(-1))  /* reserved for hidden .snap dir */
+#define CEPH_NOSNAP  ((__u64)(-2))  /* "head", "live" revision */
+#define CEPH_MAXSNAP ((__u64)(-3))  /* largest valid snapid */
+
+struct ceph_timespec {
+       __le32 tv_sec;
+       __le32 tv_nsec;
+} __attribute__ ((packed));
+
+
+/*
+ * object layout - how objects are mapped into PGs
+ */
+#define CEPH_OBJECT_LAYOUT_HASH     1
+#define CEPH_OBJECT_LAYOUT_LINEAR   2
+#define CEPH_OBJECT_LAYOUT_HASHINO  3
+
+/*
+ * pg layout -- how PGs are mapped onto (sets of) OSDs
+ */
+#define CEPH_PG_LAYOUT_CRUSH  0
+#define CEPH_PG_LAYOUT_HASH   1
+#define CEPH_PG_LAYOUT_LINEAR 2
+#define CEPH_PG_LAYOUT_HYBRID 3
+
+
+/*
+ * placement group.
+ * we encode this into one __le64.
+ */
+struct ceph_pg {
+       __le16 preferred; /* preferred primary osd */
+       __le16 ps;        /* placement seed */
+       __le32 pool;      /* object pool */
+} __attribute__ ((packed));
+
+/*
+ * pg_pool is a set of pgs storing a pool of objects
+ *
+ *  pg_num -- base number of pseudorandomly placed pgs
+ *
+ *  pgp_num -- effective number when calculating pg placement.  this
+ * is used for pg_num increases.  new pgs result in data being "split"
+ * into new pgs.  for this to proceed smoothly, new pgs are intiially
+ * colocated with their parents; that is, pgp_num doesn't increase
+ * until the new pgs have successfully split.  only _then_ are the new
+ * pgs placed independently.
+ *
+ *  lpg_num -- localized pg count (per device).  replicas are randomly
+ * selected.
+ *
+ *  lpgp_num -- as above.
+ */
+#define CEPH_PG_TYPE_REP     1
+#define CEPH_PG_TYPE_RAID4   2
+#define CEPH_PG_POOL_VERSION 2
+struct ceph_pg_pool {
+       __u8 type;                /* CEPH_PG_TYPE_* */
+       __u8 size;                /* number of osds in each pg */
+       __u8 crush_ruleset;       /* crush placement rule */
+       __u8 object_hash;         /* hash mapping object name to ps */
+       __le32 pg_num, pgp_num;   /* number of pg's */
+       __le32 lpg_num, lpgp_num; /* number of localized pg's */
+       __le32 last_change;       /* most recent epoch changed */
+       __le64 snap_seq;          /* seq for per-pool snapshot */
+       __le32 snap_epoch;        /* epoch of last snap */
+       __le32 num_snaps;
+       __le32 num_removed_snap_intervals;
+       __le64 uid;
+} __attribute__ ((packed));
+
+/*
+ * stable_mod func is used to control number of placement groups.
+ * similar to straight-up modulo, but produces a stable mapping as b
+ * increases over time.  b is the number of bins, and bmask is the
+ * containing power of 2 minus 1.
+ *
+ * b <= bmask and bmask=(2**n)-1
+ * e.g., b=12 -> bmask=15, b=123 -> bmask=127
+ */
+static inline int ceph_stable_mod(int x, int b, int bmask)
+{
+       if ((x & bmask) < b)
+               return x & bmask;
+       else
+               return x & (bmask >> 1);
+}
+
+/*
+ * object layout - how a given object should be stored.
+ */
+struct ceph_object_layout {
+       struct ceph_pg ol_pgid;   /* raw pg, with _full_ ps precision. */
+       __le32 ol_stripe_unit;    /* for per-object parity, if any */
+} __attribute__ ((packed));
+
+/*
+ * compound epoch+version, used by storage layer to serialize mutations
+ */
+struct ceph_eversion {
+       __le32 epoch;
+       __le64 version;
+} __attribute__ ((packed));
+
+/*
+ * osd map bits
+ */
+
+/* status bits */
+#define CEPH_OSD_EXISTS 1
+#define CEPH_OSD_UP     2
+
+/* osd weights.  fixed point value: 0x10000 == 1.0 ("in"), 0 == "out" */
+#define CEPH_OSD_IN  0x10000
+#define CEPH_OSD_OUT 0
+
+
+/*
+ * osd map flag bits
+ */
+#define CEPH_OSDMAP_NEARFULL (1<<0)  /* sync writes (near ENOSPC) */
+#define CEPH_OSDMAP_FULL     (1<<1)  /* no data writes (ENOSPC) */
+#define CEPH_OSDMAP_PAUSERD  (1<<2)  /* pause all reads */
+#define CEPH_OSDMAP_PAUSEWR  (1<<3)  /* pause all writes */
+#define CEPH_OSDMAP_PAUSEREC (1<<4)  /* pause recovery */
+
+/*
+ * osd ops
+ */
+#define CEPH_OSD_OP_MODE       0xf000
+#define CEPH_OSD_OP_MODE_RD    0x1000
+#define CEPH_OSD_OP_MODE_WR    0x2000
+#define CEPH_OSD_OP_MODE_RMW   0x3000
+#define CEPH_OSD_OP_MODE_SUB   0x4000
+
+#define CEPH_OSD_OP_TYPE       0x0f00
+#define CEPH_OSD_OP_TYPE_LOCK  0x0100
+#define CEPH_OSD_OP_TYPE_DATA  0x0200
+#define CEPH_OSD_OP_TYPE_ATTR  0x0300
+#define CEPH_OSD_OP_TYPE_EXEC  0x0400
+#define CEPH_OSD_OP_TYPE_PG    0x0500
+
+enum {
+       /** data **/
+       /* read */
+       CEPH_OSD_OP_READ      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 1,
+       CEPH_OSD_OP_STAT      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 2,
+
+       /* fancy read */
+       CEPH_OSD_OP_MASKTRUNC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4,
+
+       /* write */
+       CEPH_OSD_OP_WRITE     = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 1,
+       CEPH_OSD_OP_WRITEFULL = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 2,
+       CEPH_OSD_OP_TRUNCATE  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 3,
+       CEPH_OSD_OP_ZERO      = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 4,
+       CEPH_OSD_OP_DELETE    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 5,
+
+       /* fancy write */
+       CEPH_OSD_OP_APPEND    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 6,
+       CEPH_OSD_OP_STARTSYNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 7,
+       CEPH_OSD_OP_SETTRUNC  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 8,
+       CEPH_OSD_OP_TRIMTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 9,
+
+       CEPH_OSD_OP_TMAPUP  = CEPH_OSD_OP_MODE_RMW | CEPH_OSD_OP_TYPE_DATA | 10,
+       CEPH_OSD_OP_TMAPPUT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 11,
+       CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12,
+
+       CEPH_OSD_OP_CREATE  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13,
+
+       /** attrs **/
+       /* read */
+       CEPH_OSD_OP_GETXATTR  = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1,
+       CEPH_OSD_OP_GETXATTRS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 2,
+
+       /* write */
+       CEPH_OSD_OP_SETXATTR  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 1,
+       CEPH_OSD_OP_SETXATTRS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 2,
+       CEPH_OSD_OP_RESETXATTRS = CEPH_OSD_OP_MODE_WR|CEPH_OSD_OP_TYPE_ATTR | 3,
+       CEPH_OSD_OP_RMXATTR   = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 4,
+
+       /** subop **/
+       CEPH_OSD_OP_PULL           = CEPH_OSD_OP_MODE_SUB | 1,
+       CEPH_OSD_OP_PUSH           = CEPH_OSD_OP_MODE_SUB | 2,
+       CEPH_OSD_OP_BALANCEREADS   = CEPH_OSD_OP_MODE_SUB | 3,
+       CEPH_OSD_OP_UNBALANCEREADS = CEPH_OSD_OP_MODE_SUB | 4,
+       CEPH_OSD_OP_SCRUB          = CEPH_OSD_OP_MODE_SUB | 5,
+
+       /** lock **/
+       CEPH_OSD_OP_WRLOCK    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 1,
+       CEPH_OSD_OP_WRUNLOCK  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 2,
+       CEPH_OSD_OP_RDLOCK    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 3,
+       CEPH_OSD_OP_RDUNLOCK  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 4,
+       CEPH_OSD_OP_UPLOCK    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 5,
+       CEPH_OSD_OP_DNLOCK    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 6,
+
+       /** exec **/
+       CEPH_OSD_OP_CALL    = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_EXEC | 1,
+
+       /** pg **/
+       CEPH_OSD_OP_PGLS      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 1,
+};
+
+static inline int ceph_osd_op_type_lock(int op)
+{
+       return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_LOCK;
+}
+static inline int ceph_osd_op_type_data(int op)
+{
+       return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_DATA;
+}
+static inline int ceph_osd_op_type_attr(int op)
+{
+       return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_ATTR;
+}
+static inline int ceph_osd_op_type_exec(int op)
+{
+       return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_EXEC;
+}
+static inline int ceph_osd_op_type_pg(int op)
+{
+       return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_PG;
+}
+
+static inline int ceph_osd_op_mode_subop(int op)
+{
+       return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_SUB;
+}
+static inline int ceph_osd_op_mode_read(int op)
+{
+       return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_RD;
+}
+static inline int ceph_osd_op_mode_modify(int op)
+{
+       return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_WR;
+}
+
+#define CEPH_OSD_TMAP_HDR 'h'
+#define CEPH_OSD_TMAP_SET 's'
+#define CEPH_OSD_TMAP_RM  'r'
+
+extern const char *ceph_osd_op_name(int op);
+
+
+/*
+ * osd op flags
+ *
+ * An op may be READ, WRITE, or READ|WRITE.
+ */
+enum {
+       CEPH_OSD_FLAG_ACK = 1,          /* want (or is) "ack" ack */
+       CEPH_OSD_FLAG_ONNVRAM = 2,      /* want (or is) "onnvram" ack */
+       CEPH_OSD_FLAG_ONDISK = 4,       /* want (or is) "ondisk" ack */
+       CEPH_OSD_FLAG_RETRY = 8,        /* resend attempt */
+       CEPH_OSD_FLAG_READ = 16,        /* op may read */
+       CEPH_OSD_FLAG_WRITE = 32,       /* op may write */
+       CEPH_OSD_FLAG_ORDERSNAP = 64,   /* EOLDSNAP if snapc is out of order */
+       CEPH_OSD_FLAG_PEERSTAT = 128,   /* msg includes osd_peer_stat */
+       CEPH_OSD_FLAG_BALANCE_READS = 256,
+       CEPH_OSD_FLAG_PARALLELEXEC = 512, /* execute op in parallel */
+       CEPH_OSD_FLAG_PGOP = 1024,      /* pg op, no object */
+       CEPH_OSD_FLAG_EXEC = 2048,      /* op may exec */
+};
+
+enum {
+       CEPH_OSD_OP_FLAG_EXCL = 1,      /* EXCL object create */
+};
+
+#define EOLDSNAPC    ERESTART  /* ORDERSNAP flag set; writer has old snapc*/
+#define EBLACKLISTED ESHUTDOWN /* blacklisted */
+
+/*
+ * an individual object operation.  each may be accompanied by some data
+ * payload
+ */
+struct ceph_osd_op {
+       __le16 op;           /* CEPH_OSD_OP_* */
+       __le32 flags;        /* CEPH_OSD_FLAG_* */
+       union {
+               struct {
+                       __le64 offset, length;
+                       __le64 truncate_size;
+                       __le32 truncate_seq;
+               } __attribute__ ((packed)) extent;
+               struct {
+                       __le32 name_len;
+                       __le32 value_len;
+               } __attribute__ ((packed)) xattr;
+               struct {
+                       __u8 class_len;
+                       __u8 method_len;
+                       __u8 argc;
+                       __le32 indata_len;
+               } __attribute__ ((packed)) cls;
+               struct {
+                       __le64 cookie, count;
+               } __attribute__ ((packed)) pgls;
+       };
+       __le32 payload_len;
+} __attribute__ ((packed));
+
+/*
+ * osd request message header.  each request may include multiple
+ * ceph_osd_op object operations.
+ */
+struct ceph_osd_request_head {
+       __le32 client_inc;                 /* client incarnation */
+       struct ceph_object_layout layout;  /* pgid */
+       __le32 osdmap_epoch;               /* client's osdmap epoch */
+
+       __le32 flags;
+
+       struct ceph_timespec mtime;        /* for mutations only */
+       struct ceph_eversion reassert_version; /* if we are replaying op */
+
+       __le32 object_len;     /* length of object name */
+
+       __le64 snapid;         /* snapid to read */
+       __le64 snap_seq;       /* writer's snap context */
+       __le32 num_snaps;
+
+       __le16 num_ops;
+       struct ceph_osd_op ops[];  /* followed by ops[], obj, ticket, snaps */
+} __attribute__ ((packed));
+
+struct ceph_osd_reply_head {
+       __le32 client_inc;                /* client incarnation */
+       __le32 flags;
+       struct ceph_object_layout layout;
+       __le32 osdmap_epoch;
+       struct ceph_eversion reassert_version; /* for replaying uncommitted */
+
+       __le32 result;                    /* result code */
+
+       __le32 object_len;                /* length of object name */
+       __le32 num_ops;
+       struct ceph_osd_op ops[0];  /* ops[], object */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
new file mode 100644 (file)
index 0000000..bf2a5f3
--- /dev/null
@@ -0,0 +1,904 @@
+#include "ceph_debug.h"
+
+#include <linux/sort.h>
+
+#include "super.h"
+#include "decode.h"
+
+/*
+ * Snapshots in ceph are driven in large part by cooperation from the
+ * client.  In contrast to local file systems or file servers that
+ * implement snapshots at a single point in the system, ceph's
+ * distributed access to storage requires clients to help decide
+ * whether a write logically occurs before or after a recently created
+ * snapshot.
+ *
+ * This provides a perfect instantanous client-wide snapshot.  Between
+ * clients, however, snapshots may appear to be applied at slightly
+ * different points in time, depending on delays in delivering the
+ * snapshot notification.
+ *
+ * Snapshots are _not_ file system-wide.  Instead, each snapshot
+ * applies to the subdirectory nested beneath some directory.  This
+ * effectively divides the hierarchy into multiple "realms," where all
+ * of the files contained by each realm share the same set of
+ * snapshots.  An individual realm's snap set contains snapshots
+ * explicitly created on that realm, as well as any snaps in its
+ * parent's snap set _after_ the point at which the parent became it's
+ * parent (due to, say, a rename).  Similarly, snaps from prior parents
+ * during the time intervals during which they were the parent are included.
+ *
+ * The client is spared most of this detail, fortunately... it must only
+ * maintains a hierarchy of realms reflecting the current parent/child
+ * realm relationship, and for each realm has an explicit list of snaps
+ * inherited from prior parents.
+ *
+ * A snap_realm struct is maintained for realms containing every inode
+ * with an open cap in the system.  (The needed snap realm information is
+ * provided by the MDS whenever a cap is issued, i.e., on open.)  A 'seq'
+ * version number is used to ensure that as realm parameters change (new
+ * snapshot, new parent, etc.) the client's realm hierarchy is updated.
+ *
+ * The realm hierarchy drives the generation of a 'snap context' for each
+ * realm, which simply lists the resulting set of snaps for the realm.  This
+ * is attached to any writes sent to OSDs.
+ */
+/*
+ * Unfortunately error handling is a bit mixed here.  If we get a snap
+ * update, but don't have enough memory to update our realm hierarchy,
+ * it's not clear what we can do about it (besides complaining to the
+ * console).
+ */
+
+
+/*
+ * increase ref count for the realm
+ *
+ * caller must hold snap_rwsem for write.
+ */
+void ceph_get_snap_realm(struct ceph_mds_client *mdsc,
+                        struct ceph_snap_realm *realm)
+{
+       dout("get_realm %p %d -> %d\n", realm,
+            atomic_read(&realm->nref), atomic_read(&realm->nref)+1);
+       /*
+        * since we _only_ increment realm refs or empty the empty
+        * list with snap_rwsem held, adjusting the empty list here is
+        * safe.  we do need to protect against concurrent empty list
+        * additions, however.
+        */
+       if (atomic_read(&realm->nref) == 0) {
+               spin_lock(&mdsc->snap_empty_lock);
+               list_del_init(&realm->empty_item);
+               spin_unlock(&mdsc->snap_empty_lock);
+       }
+
+       atomic_inc(&realm->nref);
+}
+
+static void __insert_snap_realm(struct rb_root *root,
+                               struct ceph_snap_realm *new)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_snap_realm *r = NULL;
+
+       while (*p) {
+               parent = *p;
+               r = rb_entry(parent, struct ceph_snap_realm, node);
+               if (new->ino < r->ino)
+                       p = &(*p)->rb_left;
+               else if (new->ino > r->ino)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->node, parent, p);
+       rb_insert_color(&new->node, root);
+}
+
+/*
+ * create and get the realm rooted at @ino and bump its ref count.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+static struct ceph_snap_realm *ceph_create_snap_realm(
+       struct ceph_mds_client *mdsc,
+       u64 ino)
+{
+       struct ceph_snap_realm *realm;
+
+       realm = kzalloc(sizeof(*realm), GFP_NOFS);
+       if (!realm)
+               return ERR_PTR(-ENOMEM);
+
+       atomic_set(&realm->nref, 0);    /* tree does not take a ref */
+       realm->ino = ino;
+       INIT_LIST_HEAD(&realm->children);
+       INIT_LIST_HEAD(&realm->child_item);
+       INIT_LIST_HEAD(&realm->empty_item);
+       INIT_LIST_HEAD(&realm->inodes_with_caps);
+       spin_lock_init(&realm->inodes_with_caps_lock);
+       __insert_snap_realm(&mdsc->snap_realms, realm);
+       dout("create_snap_realm %llx %p\n", realm->ino, realm);
+       return realm;
+}
+
+/*
+ * lookup the realm rooted at @ino.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+struct ceph_snap_realm *ceph_lookup_snap_realm(struct ceph_mds_client *mdsc,
+                                              u64 ino)
+{
+       struct rb_node *n = mdsc->snap_realms.rb_node;
+       struct ceph_snap_realm *r;
+
+       while (n) {
+               r = rb_entry(n, struct ceph_snap_realm, node);
+               if (ino < r->ino)
+                       n = n->rb_left;
+               else if (ino > r->ino)
+                       n = n->rb_right;
+               else {
+                       dout("lookup_snap_realm %llx %p\n", r->ino, r);
+                       return r;
+               }
+       }
+       return NULL;
+}
+
+static void __put_snap_realm(struct ceph_mds_client *mdsc,
+                            struct ceph_snap_realm *realm);
+
+/*
+ * called with snap_rwsem (write)
+ */
+static void __destroy_snap_realm(struct ceph_mds_client *mdsc,
+                                struct ceph_snap_realm *realm)
+{
+       dout("__destroy_snap_realm %p %llx\n", realm, realm->ino);
+
+       rb_erase(&realm->node, &mdsc->snap_realms);
+
+       if (realm->parent) {
+               list_del_init(&realm->child_item);
+               __put_snap_realm(mdsc, realm->parent);
+       }
+
+       kfree(realm->prior_parent_snaps);
+       kfree(realm->snaps);
+       ceph_put_snap_context(realm->cached_context);
+       kfree(realm);
+}
+
+/*
+ * caller holds snap_rwsem (write)
+ */
+static void __put_snap_realm(struct ceph_mds_client *mdsc,
+                            struct ceph_snap_realm *realm)
+{
+       dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm,
+            atomic_read(&realm->nref), atomic_read(&realm->nref)-1);
+       if (atomic_dec_and_test(&realm->nref))
+               __destroy_snap_realm(mdsc, realm);
+}
+
+/*
+ * caller needn't hold any locks
+ */
+void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
+                        struct ceph_snap_realm *realm)
+{
+       dout("put_snap_realm %llx %p %d -> %d\n", realm->ino, realm,
+            atomic_read(&realm->nref), atomic_read(&realm->nref)-1);
+       if (!atomic_dec_and_test(&realm->nref))
+               return;
+
+       if (down_write_trylock(&mdsc->snap_rwsem)) {
+               __destroy_snap_realm(mdsc, realm);
+               up_write(&mdsc->snap_rwsem);
+       } else {
+               spin_lock(&mdsc->snap_empty_lock);
+               list_add(&mdsc->snap_empty, &realm->empty_item);
+               spin_unlock(&mdsc->snap_empty_lock);
+       }
+}
+
+/*
+ * Clean up any realms whose ref counts have dropped to zero.  Note
+ * that this does not include realms who were created but not yet
+ * used.
+ *
+ * Called under snap_rwsem (write)
+ */
+static void __cleanup_empty_realms(struct ceph_mds_client *mdsc)
+{
+       struct ceph_snap_realm *realm;
+
+       spin_lock(&mdsc->snap_empty_lock);
+       while (!list_empty(&mdsc->snap_empty)) {
+               realm = list_first_entry(&mdsc->snap_empty,
+                                  struct ceph_snap_realm, empty_item);
+               list_del(&realm->empty_item);
+               spin_unlock(&mdsc->snap_empty_lock);
+               __destroy_snap_realm(mdsc, realm);
+               spin_lock(&mdsc->snap_empty_lock);
+       }
+       spin_unlock(&mdsc->snap_empty_lock);
+}
+
+void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc)
+{
+       down_write(&mdsc->snap_rwsem);
+       __cleanup_empty_realms(mdsc);
+       up_write(&mdsc->snap_rwsem);
+}
+
+/*
+ * adjust the parent realm of a given @realm.  adjust child list, and parent
+ * pointers, and ref counts appropriately.
+ *
+ * return true if parent was changed, 0 if unchanged, <0 on error.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+static int adjust_snap_realm_parent(struct ceph_mds_client *mdsc,
+                                   struct ceph_snap_realm *realm,
+                                   u64 parentino)
+{
+       struct ceph_snap_realm *parent;
+
+       if (realm->parent_ino == parentino)
+               return 0;
+
+       parent = ceph_lookup_snap_realm(mdsc, parentino);
+       if (!parent) {
+               parent = ceph_create_snap_realm(mdsc, parentino);
+               if (IS_ERR(parent))
+                       return PTR_ERR(parent);
+       }
+       dout("adjust_snap_realm_parent %llx %p: %llx %p -> %llx %p\n",
+            realm->ino, realm, realm->parent_ino, realm->parent,
+            parentino, parent);
+       if (realm->parent) {
+               list_del_init(&realm->child_item);
+               ceph_put_snap_realm(mdsc, realm->parent);
+       }
+       realm->parent_ino = parentino;
+       realm->parent = parent;
+       ceph_get_snap_realm(mdsc, parent);
+       list_add(&realm->child_item, &parent->children);
+       return 1;
+}
+
+
+static int cmpu64_rev(const void *a, const void *b)
+{
+       if (*(u64 *)a < *(u64 *)b)
+               return 1;
+       if (*(u64 *)a > *(u64 *)b)
+               return -1;
+       return 0;
+}
+
+/*
+ * build the snap context for a given realm.
+ */
+static int build_snap_context(struct ceph_snap_realm *realm)
+{
+       struct ceph_snap_realm *parent = realm->parent;
+       struct ceph_snap_context *snapc;
+       int err = 0;
+       int i;
+       int num = realm->num_prior_parent_snaps + realm->num_snaps;
+
+       /*
+        * build parent context, if it hasn't been built.
+        * conservatively estimate that all parent snaps might be
+        * included by us.
+        */
+       if (parent) {
+               if (!parent->cached_context) {
+                       err = build_snap_context(parent);
+                       if (err)
+                               goto fail;
+               }
+               num += parent->cached_context->num_snaps;
+       }
+
+       /* do i actually need to update?  not if my context seq
+          matches realm seq, and my parents' does to.  (this works
+          because we rebuild_snap_realms() works _downward_ in
+          hierarchy after each update.) */
+       if (realm->cached_context &&
+           realm->cached_context->seq <= realm->seq &&
+           (!parent ||
+            realm->cached_context->seq <= parent->cached_context->seq)) {
+               dout("build_snap_context %llx %p: %p seq %lld (%d snaps)"
+                    " (unchanged)\n",
+                    realm->ino, realm, realm->cached_context,
+                    realm->cached_context->seq,
+                    realm->cached_context->num_snaps);
+               return 0;
+       }
+
+       /* alloc new snap context */
+       err = -ENOMEM;
+       if (num > ULONG_MAX / sizeof(u64) - sizeof(*snapc))
+               goto fail;
+       snapc = kzalloc(sizeof(*snapc) + num*sizeof(u64), GFP_NOFS);
+       if (!snapc)
+               goto fail;
+       atomic_set(&snapc->nref, 1);
+
+       /* build (reverse sorted) snap vector */
+       num = 0;
+       snapc->seq = realm->seq;
+       if (parent) {
+               /* include any of parent's snaps occuring _after_ my
+                  parent became my parent */
+               for (i = 0; i < parent->cached_context->num_snaps; i++)
+                       if (parent->cached_context->snaps[i] >=
+                           realm->parent_since)
+                               snapc->snaps[num++] =
+                                       parent->cached_context->snaps[i];
+               if (parent->cached_context->seq > snapc->seq)
+                       snapc->seq = parent->cached_context->seq;
+       }
+       memcpy(snapc->snaps + num, realm->snaps,
+              sizeof(u64)*realm->num_snaps);
+       num += realm->num_snaps;
+       memcpy(snapc->snaps + num, realm->prior_parent_snaps,
+              sizeof(u64)*realm->num_prior_parent_snaps);
+       num += realm->num_prior_parent_snaps;
+
+       sort(snapc->snaps, num, sizeof(u64), cmpu64_rev, NULL);
+       snapc->num_snaps = num;
+       dout("build_snap_context %llx %p: %p seq %lld (%d snaps)\n",
+            realm->ino, realm, snapc, snapc->seq, snapc->num_snaps);
+
+       if (realm->cached_context)
+               ceph_put_snap_context(realm->cached_context);
+       realm->cached_context = snapc;
+       return 0;
+
+fail:
+       /*
+        * if we fail, clear old (incorrect) cached_context... hopefully
+        * we'll have better luck building it later
+        */
+       if (realm->cached_context) {
+               ceph_put_snap_context(realm->cached_context);
+               realm->cached_context = NULL;
+       }
+       pr_err("build_snap_context %llx %p fail %d\n", realm->ino,
+              realm, err);
+       return err;
+}
+
+/*
+ * rebuild snap context for the given realm and all of its children.
+ */
+static void rebuild_snap_realms(struct ceph_snap_realm *realm)
+{
+       struct ceph_snap_realm *child;
+
+       dout("rebuild_snap_realms %llx %p\n", realm->ino, realm);
+       build_snap_context(realm);
+
+       list_for_each_entry(child, &realm->children, child_item)
+               rebuild_snap_realms(child);
+}
+
+
+/*
+ * helper to allocate and decode an array of snapids.  free prior
+ * instance, if any.
+ */
+static int dup_array(u64 **dst, __le64 *src, int num)
+{
+       int i;
+
+       kfree(*dst);
+       if (num) {
+               *dst = kcalloc(num, sizeof(u64), GFP_NOFS);
+               if (!*dst)
+                       return -ENOMEM;
+               for (i = 0; i < num; i++)
+                       (*dst)[i] = get_unaligned_le64(src + i);
+       } else {
+               *dst = NULL;
+       }
+       return 0;
+}
+
+
+/*
+ * When a snapshot is applied, the size/mtime inode metadata is queued
+ * in a ceph_cap_snap (one for each snapshot) until writeback
+ * completes and the metadata can be flushed back to the MDS.
+ *
+ * However, if a (sync) write is currently in-progress when we apply
+ * the snapshot, we have to wait until the write succeeds or fails
+ * (and a final size/mtime is known).  In this case the
+ * cap_snap->writing = 1, and is said to be "pending."  When the write
+ * finishes, we __ceph_finish_cap_snap().
+ *
+ * Caller must hold snap_rwsem for read (i.e., the realm topology won't
+ * change).
+ */
+void ceph_queue_cap_snap(struct ceph_inode_info *ci,
+                        struct ceph_snap_context *snapc)
+{
+       struct inode *inode = &ci->vfs_inode;
+       struct ceph_cap_snap *capsnap;
+       int used;
+
+       capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS);
+       if (!capsnap) {
+               pr_err("ENOMEM allocating ceph_cap_snap on %p\n", inode);
+               return;
+       }
+
+       spin_lock(&inode->i_lock);
+       used = __ceph_caps_used(ci);
+       if (__ceph_have_pending_cap_snap(ci)) {
+               /* there is no point in queuing multiple "pending" cap_snaps,
+                  as no new writes are allowed to start when pending, so any
+                  writes in progress now were started before the previous
+                  cap_snap.  lucky us. */
+               dout("queue_cap_snap %p snapc %p seq %llu used %d"
+                    " already pending\n", inode, snapc, snapc->seq, used);
+               kfree(capsnap);
+       } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) {
+               igrab(inode);
+
+               atomic_set(&capsnap->nref, 1);
+               capsnap->ci = ci;
+               INIT_LIST_HEAD(&capsnap->ci_item);
+               INIT_LIST_HEAD(&capsnap->flushing_item);
+
+               capsnap->follows = snapc->seq - 1;
+               capsnap->context = ceph_get_snap_context(snapc);
+               capsnap->issued = __ceph_caps_issued(ci, NULL);
+               capsnap->dirty = __ceph_caps_dirty(ci);
+
+               capsnap->mode = inode->i_mode;
+               capsnap->uid = inode->i_uid;
+               capsnap->gid = inode->i_gid;
+
+               /* fixme? */
+               capsnap->xattr_blob = NULL;
+               capsnap->xattr_len = 0;
+
+               /* dirty page count moved from _head to this cap_snap;
+                  all subsequent writes page dirties occur _after_ this
+                  snapshot. */
+               capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
+               ci->i_wrbuffer_ref_head = 0;
+               ceph_put_snap_context(ci->i_head_snapc);
+               ci->i_head_snapc = NULL;
+               list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
+
+               if (used & CEPH_CAP_FILE_WR) {
+                       dout("queue_cap_snap %p cap_snap %p snapc %p"
+                            " seq %llu used WR, now pending\n", inode,
+                            capsnap, snapc, snapc->seq);
+                       capsnap->writing = 1;
+               } else {
+                       /* note mtime, size NOW. */
+                       __ceph_finish_cap_snap(ci, capsnap);
+               }
+       } else {
+               dout("queue_cap_snap %p nothing dirty|writing\n", inode);
+               kfree(capsnap);
+       }
+
+       spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Finalize the size, mtime for a cap_snap.. that is, settle on final values
+ * to be used for the snapshot, to be flushed back to the mds.
+ *
+ * If capsnap can now be flushed, add to snap_flush list, and return 1.
+ *
+ * Caller must hold i_lock.
+ */
+int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
+                           struct ceph_cap_snap *capsnap)
+{
+       struct inode *inode = &ci->vfs_inode;
+       struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+
+       BUG_ON(capsnap->writing);
+       capsnap->size = inode->i_size;
+       capsnap->mtime = inode->i_mtime;
+       capsnap->atime = inode->i_atime;
+       capsnap->ctime = inode->i_ctime;
+       capsnap->time_warp_seq = ci->i_time_warp_seq;
+       if (capsnap->dirty_pages) {
+               dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu "
+                    "still has %d dirty pages\n", inode, capsnap,
+                    capsnap->context, capsnap->context->seq,
+                    capsnap->size, capsnap->dirty_pages);
+               return 0;
+       }
+       dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu clean\n",
+            inode, capsnap, capsnap->context,
+            capsnap->context->seq, capsnap->size);
+
+       spin_lock(&mdsc->snap_flush_lock);
+       list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
+       spin_unlock(&mdsc->snap_flush_lock);
+       return 1;  /* caller may want to ceph_flush_snaps */
+}
+
+
+/*
+ * Parse and apply a snapblob "snap trace" from the MDS.  This specifies
+ * the snap realm parameters from a given realm and all of its ancestors,
+ * up to the root.
+ *
+ * Caller must hold snap_rwsem for write.
+ */
+int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
+                          void *p, void *e, bool deletion)
+{
+       struct ceph_mds_snap_realm *ri;    /* encoded */
+       __le64 *snaps;                     /* encoded */
+       __le64 *prior_parent_snaps;        /* encoded */
+       struct ceph_snap_realm *realm;
+       int invalidate = 0;
+       int err = -ENOMEM;
+
+       dout("update_snap_trace deletion=%d\n", deletion);
+more:
+       ceph_decode_need(&p, e, sizeof(*ri), bad);
+       ri = p;
+       p += sizeof(*ri);
+       ceph_decode_need(&p, e, sizeof(u64)*(le32_to_cpu(ri->num_snaps) +
+                           le32_to_cpu(ri->num_prior_parent_snaps)), bad);
+       snaps = p;
+       p += sizeof(u64) * le32_to_cpu(ri->num_snaps);
+       prior_parent_snaps = p;
+       p += sizeof(u64) * le32_to_cpu(ri->num_prior_parent_snaps);
+
+       realm = ceph_lookup_snap_realm(mdsc, le64_to_cpu(ri->ino));
+       if (!realm) {
+               realm = ceph_create_snap_realm(mdsc, le64_to_cpu(ri->ino));
+               if (IS_ERR(realm)) {
+                       err = PTR_ERR(realm);
+                       goto fail;
+               }
+       }
+
+       if (le64_to_cpu(ri->seq) > realm->seq) {
+               dout("update_snap_trace updating %llx %p %lld -> %lld\n",
+                    realm->ino, realm, realm->seq, le64_to_cpu(ri->seq));
+               /*
+                * if the realm seq has changed, queue a cap_snap for every
+                * inode with open caps.  we do this _before_ we update
+                * the realm info so that we prepare for writeback under the
+                * _previous_ snap context.
+                *
+                * ...unless it's a snap deletion!
+                */
+               if (!deletion) {
+                       struct ceph_inode_info *ci;
+                       struct inode *lastinode = NULL;
+
+                       spin_lock(&realm->inodes_with_caps_lock);
+                       list_for_each_entry(ci, &realm->inodes_with_caps,
+                                           i_snap_realm_item) {
+                               struct inode *inode = igrab(&ci->vfs_inode);
+                               if (!inode)
+                                       continue;
+                               spin_unlock(&realm->inodes_with_caps_lock);
+                               if (lastinode)
+                                       iput(lastinode);
+                               lastinode = inode;
+                               ceph_queue_cap_snap(ci, realm->cached_context);
+                               spin_lock(&realm->inodes_with_caps_lock);
+                       }
+                       spin_unlock(&realm->inodes_with_caps_lock);
+                       if (lastinode)
+                               iput(lastinode);
+                       dout("update_snap_trace cap_snaps queued\n");
+               }
+
+       } else {
+               dout("update_snap_trace %llx %p seq %lld unchanged\n",
+                    realm->ino, realm, realm->seq);
+       }
+
+       /* ensure the parent is correct */
+       err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent));
+       if (err < 0)
+               goto fail;
+       invalidate += err;
+
+       if (le64_to_cpu(ri->seq) > realm->seq) {
+               /* update realm parameters, snap lists */
+               realm->seq = le64_to_cpu(ri->seq);
+               realm->created = le64_to_cpu(ri->created);
+               realm->parent_since = le64_to_cpu(ri->parent_since);
+
+               realm->num_snaps = le32_to_cpu(ri->num_snaps);
+               err = dup_array(&realm->snaps, snaps, realm->num_snaps);
+               if (err < 0)
+                       goto fail;
+
+               realm->num_prior_parent_snaps =
+                       le32_to_cpu(ri->num_prior_parent_snaps);
+               err = dup_array(&realm->prior_parent_snaps, prior_parent_snaps,
+                               realm->num_prior_parent_snaps);
+               if (err < 0)
+                       goto fail;
+
+               invalidate = 1;
+       } else if (!realm->cached_context) {
+               invalidate = 1;
+       }
+
+       dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino,
+            realm, invalidate, p, e);
+
+       if (p < e)
+               goto more;
+
+       /* invalidate when we reach the _end_ (root) of the trace */
+       if (invalidate)
+               rebuild_snap_realms(realm);
+
+       __cleanup_empty_realms(mdsc);
+       return 0;
+
+bad:
+       err = -EINVAL;
+fail:
+       pr_err("update_snap_trace error %d\n", err);
+       return err;
+}
+
+
+/*
+ * Send any cap_snaps that are queued for flush.  Try to carry
+ * s_mutex across multiple snap flushes to avoid locking overhead.
+ *
+ * Caller holds no locks.
+ */
+static void flush_snaps(struct ceph_mds_client *mdsc)
+{
+       struct ceph_inode_info *ci;
+       struct inode *inode;
+       struct ceph_mds_session *session = NULL;
+
+       dout("flush_snaps\n");
+       spin_lock(&mdsc->snap_flush_lock);
+       while (!list_empty(&mdsc->snap_flush_list)) {
+               ci = list_first_entry(&mdsc->snap_flush_list,
+                               struct ceph_inode_info, i_snap_flush_item);
+               inode = &ci->vfs_inode;
+               igrab(inode);
+               spin_unlock(&mdsc->snap_flush_lock);
+               spin_lock(&inode->i_lock);
+               __ceph_flush_snaps(ci, &session);
+               spin_unlock(&inode->i_lock);
+               iput(inode);
+               spin_lock(&mdsc->snap_flush_lock);
+       }
+       spin_unlock(&mdsc->snap_flush_lock);
+
+       if (session) {
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+       }
+       dout("flush_snaps done\n");
+}
+
+
+/*
+ * Handle a snap notification from the MDS.
+ *
+ * This can take two basic forms: the simplest is just a snap creation
+ * or deletion notification on an existing realm.  This should update the
+ * realm and its children.
+ *
+ * The more difficult case is realm creation, due to snap creation at a
+ * new point in the file hierarchy, or due to a rename that moves a file or
+ * directory into another realm.
+ */
+void ceph_handle_snap(struct ceph_mds_client *mdsc,
+                     struct ceph_mds_session *session,
+                     struct ceph_msg *msg)
+{
+       struct super_block *sb = mdsc->client->sb;
+       int mds = session->s_mds;
+       u64 split;
+       int op;
+       int trace_len;
+       struct ceph_snap_realm *realm = NULL;
+       void *p = msg->front.iov_base;
+       void *e = p + msg->front.iov_len;
+       struct ceph_mds_snap_head *h;
+       int num_split_inos, num_split_realms;
+       __le64 *split_inos = NULL, *split_realms = NULL;
+       int i;
+       int locked_rwsem = 0;
+
+       /* decode */
+       if (msg->front.iov_len < sizeof(*h))
+               goto bad;
+       h = p;
+       op = le32_to_cpu(h->op);
+       split = le64_to_cpu(h->split);   /* non-zero if we are splitting an
+                                         * existing realm */
+       num_split_inos = le32_to_cpu(h->num_split_inos);
+       num_split_realms = le32_to_cpu(h->num_split_realms);
+       trace_len = le32_to_cpu(h->trace_len);
+       p += sizeof(*h);
+
+       dout("handle_snap from mds%d op %s split %llx tracelen %d\n", mds,
+            ceph_snap_op_name(op), split, trace_len);
+
+       mutex_lock(&session->s_mutex);
+       session->s_seq++;
+       mutex_unlock(&session->s_mutex);
+
+       down_write(&mdsc->snap_rwsem);
+       locked_rwsem = 1;
+
+       if (op == CEPH_SNAP_OP_SPLIT) {
+               struct ceph_mds_snap_realm *ri;
+
+               /*
+                * A "split" breaks part of an existing realm off into
+                * a new realm.  The MDS provides a list of inodes
+                * (with caps) and child realms that belong to the new
+                * child.
+                */
+               split_inos = p;
+               p += sizeof(u64) * num_split_inos;
+               split_realms = p;
+               p += sizeof(u64) * num_split_realms;
+               ceph_decode_need(&p, e, sizeof(*ri), bad);
+               /* we will peek at realm info here, but will _not_
+                * advance p, as the realm update will occur below in
+                * ceph_update_snap_trace. */
+               ri = p;
+
+               realm = ceph_lookup_snap_realm(mdsc, split);
+               if (!realm) {
+                       realm = ceph_create_snap_realm(mdsc, split);
+                       if (IS_ERR(realm))
+                               goto out;
+               }
+               ceph_get_snap_realm(mdsc, realm);
+
+               dout("splitting snap_realm %llx %p\n", realm->ino, realm);
+               for (i = 0; i < num_split_inos; i++) {
+                       struct ceph_vino vino = {
+                               .ino = le64_to_cpu(split_inos[i]),
+                               .snap = CEPH_NOSNAP,
+                       };
+                       struct inode *inode = ceph_find_inode(sb, vino);
+                       struct ceph_inode_info *ci;
+
+                       if (!inode)
+                               continue;
+                       ci = ceph_inode(inode);
+
+                       spin_lock(&inode->i_lock);
+                       if (!ci->i_snap_realm)
+                               goto skip_inode;
+                       /*
+                        * If this inode belongs to a realm that was
+                        * created after our new realm, we experienced
+                        * a race (due to another split notifications
+                        * arriving from a different MDS).  So skip
+                        * this inode.
+                        */
+                       if (ci->i_snap_realm->created >
+                           le64_to_cpu(ri->created)) {
+                               dout(" leaving %p in newer realm %llx %p\n",
+                                    inode, ci->i_snap_realm->ino,
+                                    ci->i_snap_realm);
+                               goto skip_inode;
+                       }
+                       dout(" will move %p to split realm %llx %p\n",
+                            inode, realm->ino, realm);
+                       /*
+                        * Remove the inode from the realm's inode
+                        * list, but don't add it to the new realm
+                        * yet.  We don't want the cap_snap to be
+                        * queued (again) by ceph_update_snap_trace()
+                        * below.  Queue it _now_, under the old context.
+                        */
+                       list_del_init(&ci->i_snap_realm_item);
+                       spin_unlock(&inode->i_lock);
+
+                       ceph_queue_cap_snap(ci,
+                                           ci->i_snap_realm->cached_context);
+
+                       iput(inode);
+                       continue;
+
+skip_inode:
+                       spin_unlock(&inode->i_lock);
+                       iput(inode);
+               }
+
+               /* we may have taken some of the old realm's children. */
+               for (i = 0; i < num_split_realms; i++) {
+                       struct ceph_snap_realm *child =
+                               ceph_lookup_snap_realm(mdsc,
+                                          le64_to_cpu(split_realms[i]));
+                       if (!child)
+                               continue;
+                       adjust_snap_realm_parent(mdsc, child, realm->ino);
+               }
+       }
+
+       /*
+        * update using the provided snap trace. if we are deleting a
+        * snap, we can avoid queueing cap_snaps.
+        */
+       ceph_update_snap_trace(mdsc, p, e,
+                              op == CEPH_SNAP_OP_DESTROY);
+
+       if (op == CEPH_SNAP_OP_SPLIT) {
+               /*
+                * ok, _now_ add the inodes into the new realm.
+                */
+               for (i = 0; i < num_split_inos; i++) {
+                       struct ceph_vino vino = {
+                               .ino = le64_to_cpu(split_inos[i]),
+                               .snap = CEPH_NOSNAP,
+                       };
+                       struct inode *inode = ceph_find_inode(sb, vino);
+                       struct ceph_inode_info *ci;
+
+                       if (!inode)
+                               continue;
+                       ci = ceph_inode(inode);
+                       spin_lock(&inode->i_lock);
+                       if (!ci->i_snap_realm)
+                               goto split_skip_inode;
+                       ceph_put_snap_realm(mdsc, ci->i_snap_realm);
+                       spin_lock(&realm->inodes_with_caps_lock);
+                       list_add(&ci->i_snap_realm_item,
+                                &realm->inodes_with_caps);
+                       ci->i_snap_realm = realm;
+                       spin_unlock(&realm->inodes_with_caps_lock);
+                       ceph_get_snap_realm(mdsc, realm);
+split_skip_inode:
+                       spin_unlock(&inode->i_lock);
+                       iput(inode);
+               }
+
+               /* we took a reference when we created the realm, above */
+               ceph_put_snap_realm(mdsc, realm);
+       }
+
+       __cleanup_empty_realms(mdsc);
+
+       up_write(&mdsc->snap_rwsem);
+
+       flush_snaps(mdsc);
+       return;
+
+bad:
+       pr_err("corrupt snap message from mds%d\n", mds);
+       ceph_msg_dump(msg);
+out:
+       if (locked_rwsem)
+               up_write(&mdsc->snap_rwsem);
+       return;
+}
+
+
+
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
new file mode 100644 (file)
index 0000000..4290a6e
--- /dev/null
@@ -0,0 +1,1030 @@
+
+#include "ceph_debug.h"
+
+#include <linux/backing-dev.h>
+#include <linux/fs.h>
+#include <linux/inet.h>
+#include <linux/in6.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/parser.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include "decode.h"
+#include "super.h"
+#include "mon_client.h"
+#include "auth.h"
+
+/*
+ * Ceph superblock operations
+ *
+ * Handle the basics of mounting, unmounting.
+ */
+
+
+/*
+ * find filename portion of a path (/foo/bar/baz -> baz)
+ */
+const char *ceph_file_part(const char *s, int len)
+{
+       const char *e = s + len;
+
+       while (e != s && *(e-1) != '/')
+               e--;
+       return e;
+}
+
+
+/*
+ * super ops
+ */
+static void ceph_put_super(struct super_block *s)
+{
+       struct ceph_client *cl = ceph_client(s);
+
+       dout("put_super\n");
+       ceph_mdsc_close_sessions(&cl->mdsc);
+       return;
+}
+
+static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct ceph_client *client = ceph_inode_to_client(dentry->d_inode);
+       struct ceph_monmap *monmap = client->monc.monmap;
+       struct ceph_statfs st;
+       u64 fsid;
+       int err;
+
+       dout("statfs\n");
+       err = ceph_monc_do_statfs(&client->monc, &st);
+       if (err < 0)
+               return err;
+
+       /* fill in kstatfs */
+       buf->f_type = CEPH_SUPER_MAGIC;  /* ?? */
+
+       /*
+        * express utilization in terms of large blocks to avoid
+        * overflow on 32-bit machines.
+        */
+       buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
+       buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
+       buf->f_bfree = (le64_to_cpu(st.kb) - le64_to_cpu(st.kb_used)) >>
+               (CEPH_BLOCK_SHIFT-10);
+       buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
+
+       buf->f_files = le64_to_cpu(st.num_objects);
+       buf->f_ffree = -1;
+       buf->f_namelen = PATH_MAX;
+       buf->f_frsize = PAGE_CACHE_SIZE;
+
+       /* leave fsid little-endian, regardless of host endianness */
+       fsid = *(u64 *)(&monmap->fsid) ^ *((u64 *)&monmap->fsid + 1);
+       buf->f_fsid.val[0] = fsid & 0xffffffff;
+       buf->f_fsid.val[1] = fsid >> 32;
+
+       return 0;
+}
+
+
+static int ceph_syncfs(struct super_block *sb, int wait)
+{
+       dout("sync_fs %d\n", wait);
+       ceph_osdc_sync(&ceph_client(sb)->osdc);
+       ceph_mdsc_sync(&ceph_client(sb)->mdsc);
+       dout("sync_fs %d done\n", wait);
+       return 0;
+}
+
+
+/**
+ * ceph_show_options - Show mount options in /proc/mounts
+ * @m: seq_file to write to
+ * @mnt: mount descriptor
+ */
+static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+       struct ceph_client *client = ceph_sb_to_client(mnt->mnt_sb);
+       struct ceph_mount_args *args = client->mount_args;
+
+       if (args->flags & CEPH_OPT_FSID)
+               seq_printf(m, ",fsidmajor=%llu,fsidminor%llu",
+                          le64_to_cpu(*(__le64 *)&args->fsid.fsid[0]),
+                          le64_to_cpu(*(__le64 *)&args->fsid.fsid[8]));
+       if (args->flags & CEPH_OPT_NOSHARE)
+               seq_puts(m, ",noshare");
+       if (args->flags & CEPH_OPT_DIRSTAT)
+               seq_puts(m, ",dirstat");
+       if ((args->flags & CEPH_OPT_RBYTES) == 0)
+               seq_puts(m, ",norbytes");
+       if (args->flags & CEPH_OPT_NOCRC)
+               seq_puts(m, ",nocrc");
+       if (args->flags & CEPH_OPT_NOASYNCREADDIR)
+               seq_puts(m, ",noasyncreaddir");
+       if (strcmp(args->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
+               seq_printf(m, ",snapdirname=%s", args->snapdir_name);
+       if (args->name)
+               seq_printf(m, ",name=%s", args->name);
+       if (args->secret)
+               seq_puts(m, ",secret=<hidden>");
+       return 0;
+}
+
+/*
+ * caches
+ */
+struct kmem_cache *ceph_inode_cachep;
+struct kmem_cache *ceph_cap_cachep;
+struct kmem_cache *ceph_dentry_cachep;
+struct kmem_cache *ceph_file_cachep;
+
+static void ceph_inode_init_once(void *foo)
+{
+       struct ceph_inode_info *ci = foo;
+       inode_init_once(&ci->vfs_inode);
+}
+
+static int default_congestion_kb(void)
+{
+       int congestion_kb;
+
+       /*
+        * Copied from NFS
+        *
+        * congestion size, scale with available memory.
+        *
+        *  64MB:    8192k
+        * 128MB:   11585k
+        * 256MB:   16384k
+        * 512MB:   23170k
+        *   1GB:   32768k
+        *   2GB:   46340k
+        *   4GB:   65536k
+        *   8GB:   92681k
+        *  16GB:  131072k
+        *
+        * This allows larger machines to have larger/more transfers.
+        * Limit the default to 256M
+        */
+       congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
+       if (congestion_kb > 256*1024)
+               congestion_kb = 256*1024;
+
+       return congestion_kb;
+}
+
+static int __init init_caches(void)
+{
+       ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
+                                     sizeof(struct ceph_inode_info),
+                                     __alignof__(struct ceph_inode_info),
+                                     (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
+                                     ceph_inode_init_once);
+       if (ceph_inode_cachep == NULL)
+               return -ENOMEM;
+
+       ceph_cap_cachep = KMEM_CACHE(ceph_cap,
+                                    SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_cap_cachep == NULL)
+               goto bad_cap;
+
+       ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
+                                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_dentry_cachep == NULL)
+               goto bad_dentry;
+
+       ceph_file_cachep = KMEM_CACHE(ceph_file_info,
+                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_file_cachep == NULL)
+               goto bad_file;
+
+       return 0;
+
+bad_file:
+       kmem_cache_destroy(ceph_dentry_cachep);
+bad_dentry:
+       kmem_cache_destroy(ceph_cap_cachep);
+bad_cap:
+       kmem_cache_destroy(ceph_inode_cachep);
+       return -ENOMEM;
+}
+
+static void destroy_caches(void)
+{
+       kmem_cache_destroy(ceph_inode_cachep);
+       kmem_cache_destroy(ceph_cap_cachep);
+       kmem_cache_destroy(ceph_dentry_cachep);
+       kmem_cache_destroy(ceph_file_cachep);
+}
+
+
+/*
+ * ceph_umount_begin - initiate forced umount.  Tear down down the
+ * mount, skipping steps that may hang while waiting for server(s).
+ */
+static void ceph_umount_begin(struct super_block *sb)
+{
+       struct ceph_client *client = ceph_sb_to_client(sb);
+
+       dout("ceph_umount_begin - starting forced umount\n");
+       if (!client)
+               return;
+       client->mount_state = CEPH_MOUNT_SHUTDOWN;
+       return;
+}
+
+static const struct super_operations ceph_super_ops = {
+       .alloc_inode    = ceph_alloc_inode,
+       .destroy_inode  = ceph_destroy_inode,
+       .write_inode    = ceph_write_inode,
+       .sync_fs        = ceph_syncfs,
+       .put_super      = ceph_put_super,
+       .show_options   = ceph_show_options,
+       .statfs         = ceph_statfs,
+       .umount_begin   = ceph_umount_begin,
+};
+
+
+const char *ceph_msg_type_name(int type)
+{
+       switch (type) {
+       case CEPH_MSG_SHUTDOWN: return "shutdown";
+       case CEPH_MSG_PING: return "ping";
+       case CEPH_MSG_AUTH: return "auth";
+       case CEPH_MSG_AUTH_REPLY: return "auth_reply";
+       case CEPH_MSG_MON_MAP: return "mon_map";
+       case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
+       case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
+       case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
+       case CEPH_MSG_STATFS: return "statfs";
+       case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
+       case CEPH_MSG_MDS_MAP: return "mds_map";
+       case CEPH_MSG_CLIENT_SESSION: return "client_session";
+       case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
+       case CEPH_MSG_CLIENT_REQUEST: return "client_request";
+       case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
+       case CEPH_MSG_CLIENT_REPLY: return "client_reply";
+       case CEPH_MSG_CLIENT_CAPS: return "client_caps";
+       case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
+       case CEPH_MSG_CLIENT_SNAP: return "client_snap";
+       case CEPH_MSG_CLIENT_LEASE: return "client_lease";
+       case CEPH_MSG_OSD_MAP: return "osd_map";
+       case CEPH_MSG_OSD_OP: return "osd_op";
+       case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
+       default: return "unknown";
+       }
+}
+
+
+/*
+ * mount options
+ */
+enum {
+       Opt_fsidmajor,
+       Opt_fsidminor,
+       Opt_monport,
+       Opt_wsize,
+       Opt_rsize,
+       Opt_osdtimeout,
+       Opt_osdkeepalivetimeout,
+       Opt_mount_timeout,
+       Opt_osd_idle_ttl,
+       Opt_caps_wanted_delay_min,
+       Opt_caps_wanted_delay_max,
+       Opt_readdir_max_entries,
+       Opt_congestion_kb,
+       Opt_last_int,
+       /* int args above */
+       Opt_snapdirname,
+       Opt_name,
+       Opt_secret,
+       Opt_last_string,
+       /* string args above */
+       Opt_ip,
+       Opt_noshare,
+       Opt_dirstat,
+       Opt_nodirstat,
+       Opt_rbytes,
+       Opt_norbytes,
+       Opt_nocrc,
+       Opt_noasyncreaddir,
+};
+
+static match_table_t arg_tokens = {
+       {Opt_fsidmajor, "fsidmajor=%ld"},
+       {Opt_fsidminor, "fsidminor=%ld"},
+       {Opt_monport, "monport=%d"},
+       {Opt_wsize, "wsize=%d"},
+       {Opt_rsize, "rsize=%d"},
+       {Opt_osdtimeout, "osdtimeout=%d"},
+       {Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
+       {Opt_mount_timeout, "mount_timeout=%d"},
+       {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
+       {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
+       {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
+       {Opt_readdir_max_entries, "readdir_max_entries=%d"},
+       {Opt_congestion_kb, "write_congestion_kb=%d"},
+       /* int args above */
+       {Opt_snapdirname, "snapdirname=%s"},
+       {Opt_name, "name=%s"},
+       {Opt_secret, "secret=%s"},
+       /* string args above */
+       {Opt_ip, "ip=%s"},
+       {Opt_noshare, "noshare"},
+       {Opt_dirstat, "dirstat"},
+       {Opt_nodirstat, "nodirstat"},
+       {Opt_rbytes, "rbytes"},
+       {Opt_norbytes, "norbytes"},
+       {Opt_nocrc, "nocrc"},
+       {Opt_noasyncreaddir, "noasyncreaddir"},
+       {-1, NULL}
+};
+
+
+static struct ceph_mount_args *parse_mount_args(int flags, char *options,
+                                               const char *dev_name,
+                                               const char **path)
+{
+       struct ceph_mount_args *args;
+       const char *c;
+       int err = -ENOMEM;
+       substring_t argstr[MAX_OPT_ARGS];
+
+       args = kzalloc(sizeof(*args), GFP_KERNEL);
+       if (!args)
+               return ERR_PTR(-ENOMEM);
+       args->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*args->mon_addr),
+                                GFP_KERNEL);
+       if (!args->mon_addr)
+               goto out;
+
+       dout("parse_mount_args %p, dev_name '%s'\n", args, dev_name);
+
+       /* start with defaults */
+       args->sb_flags = flags;
+       args->flags = CEPH_OPT_DEFAULT;
+       args->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT;
+       args->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
+       args->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
+       args->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;   /* seconds */
+       args->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+       args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
+       args->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
+       args->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+       args->cap_release_safety = CEPH_CAPS_PER_RELEASE * 4;
+       args->max_readdir = 1024;
+       args->congestion_kb = default_congestion_kb();
+
+       /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
+       err = -EINVAL;
+       if (!dev_name)
+               goto out;
+       *path = strstr(dev_name, ":/");
+       if (*path == NULL) {
+               pr_err("device name is missing path (no :/ in %s)\n",
+                      dev_name);
+               goto out;
+       }
+
+       /* get mon ip(s) */
+       err = ceph_parse_ips(dev_name, *path, args->mon_addr,
+                            CEPH_MAX_MON, &args->num_mon);
+       if (err < 0)
+               goto out;
+
+       /* path on server */
+       *path += 2;
+       dout("server path '%s'\n", *path);
+
+       /* parse mount options */
+       while ((c = strsep(&options, ",")) != NULL) {
+               int token, intval, ret;
+               if (!*c)
+                       continue;
+               err = -EINVAL;
+               token = match_token((char *)c, arg_tokens, argstr);
+               if (token < 0) {
+                       pr_err("bad mount option at '%s'\n", c);
+                       goto out;
+               }
+               if (token < Opt_last_int) {
+                       ret = match_int(&argstr[0], &intval);
+                       if (ret < 0) {
+                               pr_err("bad mount option arg (not int) "
+                                      "at '%s'\n", c);
+                               continue;
+                       }
+                       dout("got int token %d val %d\n", token, intval);
+               } else if (token > Opt_last_int && token < Opt_last_string) {
+                       dout("got string token %d val %s\n", token,
+                            argstr[0].from);
+               } else {
+                       dout("got token %d\n", token);
+               }
+               switch (token) {
+               case Opt_fsidmajor:
+                       *(__le64 *)&args->fsid.fsid[0] = cpu_to_le64(intval);
+                       break;
+               case Opt_fsidminor:
+                       *(__le64 *)&args->fsid.fsid[8] = cpu_to_le64(intval);
+                       break;
+               case Opt_ip:
+                       err = ceph_parse_ips(argstr[0].from,
+                                            argstr[0].to,
+                                            &args->my_addr,
+                                            1, NULL);
+                       if (err < 0)
+                               goto out;
+                       args->flags |= CEPH_OPT_MYIP;
+                       break;
+
+               case Opt_snapdirname:
+                       kfree(args->snapdir_name);
+                       args->snapdir_name = kstrndup(argstr[0].from,
+                                             argstr[0].to-argstr[0].from,
+                                             GFP_KERNEL);
+                       break;
+               case Opt_name:
+                       args->name = kstrndup(argstr[0].from,
+                                             argstr[0].to-argstr[0].from,
+                                             GFP_KERNEL);
+                       break;
+               case Opt_secret:
+                       args->secret = kstrndup(argstr[0].from,
+                                               argstr[0].to-argstr[0].from,
+                                               GFP_KERNEL);
+                       break;
+
+                       /* misc */
+               case Opt_wsize:
+                       args->wsize = intval;
+                       break;
+               case Opt_rsize:
+                       args->rsize = intval;
+                       break;
+               case Opt_osdtimeout:
+                       args->osd_timeout = intval;
+                       break;
+               case Opt_osdkeepalivetimeout:
+                       args->osd_keepalive_timeout = intval;
+                       break;
+               case Opt_mount_timeout:
+                       args->mount_timeout = intval;
+                       break;
+               case Opt_caps_wanted_delay_min:
+                       args->caps_wanted_delay_min = intval;
+                       break;
+               case Opt_caps_wanted_delay_max:
+                       args->caps_wanted_delay_max = intval;
+                       break;
+               case Opt_readdir_max_entries:
+                       args->max_readdir = intval;
+                       break;
+               case Opt_congestion_kb:
+                       args->congestion_kb = intval;
+                       break;
+
+               case Opt_noshare:
+                       args->flags |= CEPH_OPT_NOSHARE;
+                       break;
+
+               case Opt_dirstat:
+                       args->flags |= CEPH_OPT_DIRSTAT;
+                       break;
+               case Opt_nodirstat:
+                       args->flags &= ~CEPH_OPT_DIRSTAT;
+                       break;
+               case Opt_rbytes:
+                       args->flags |= CEPH_OPT_RBYTES;
+                       break;
+               case Opt_norbytes:
+                       args->flags &= ~CEPH_OPT_RBYTES;
+                       break;
+               case Opt_nocrc:
+                       args->flags |= CEPH_OPT_NOCRC;
+                       break;
+               case Opt_noasyncreaddir:
+                       args->flags |= CEPH_OPT_NOASYNCREADDIR;
+                       break;
+
+               default:
+                       BUG_ON(token);
+               }
+       }
+       return args;
+
+out:
+       kfree(args->mon_addr);
+       kfree(args);
+       return ERR_PTR(err);
+}
+
+static void destroy_mount_args(struct ceph_mount_args *args)
+{
+       dout("destroy_mount_args %p\n", args);
+       kfree(args->snapdir_name);
+       args->snapdir_name = NULL;
+       kfree(args->name);
+       args->name = NULL;
+       kfree(args->secret);
+       args->secret = NULL;
+       kfree(args);
+}
+
+/*
+ * create a fresh client instance
+ */
+static struct ceph_client *ceph_create_client(struct ceph_mount_args *args)
+{
+       struct ceph_client *client;
+       int err = -ENOMEM;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_init(&client->mount_mutex);
+
+       init_waitqueue_head(&client->auth_wq);
+
+       client->sb = NULL;
+       client->mount_state = CEPH_MOUNT_MOUNTING;
+       client->mount_args = args;
+
+       client->msgr = NULL;
+
+       client->auth_err = 0;
+       atomic_long_set(&client->writeback_count, 0);
+
+       err = bdi_init(&client->backing_dev_info);
+       if (err < 0)
+               goto fail;
+
+       err = -ENOMEM;
+       client->wb_wq = create_workqueue("ceph-writeback");
+       if (client->wb_wq == NULL)
+               goto fail_bdi;
+       client->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid");
+       if (client->pg_inv_wq == NULL)
+               goto fail_wb_wq;
+       client->trunc_wq = create_singlethread_workqueue("ceph-trunc");
+       if (client->trunc_wq == NULL)
+               goto fail_pg_inv_wq;
+
+       /* set up mempools */
+       err = -ENOMEM;
+       client->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
+                             client->mount_args->wsize >> PAGE_CACHE_SHIFT);
+       if (!client->wb_pagevec_pool)
+               goto fail_trunc_wq;
+
+       /* caps */
+       client->min_caps = args->max_readdir;
+       ceph_adjust_min_caps(client->min_caps);
+
+       /* subsystems */
+       err = ceph_monc_init(&client->monc, client);
+       if (err < 0)
+               goto fail_mempool;
+       err = ceph_osdc_init(&client->osdc, client);
+       if (err < 0)
+               goto fail_monc;
+       err = ceph_mdsc_init(&client->mdsc, client);
+       if (err < 0)
+               goto fail_osdc;
+       return client;
+
+fail_osdc:
+       ceph_osdc_stop(&client->osdc);
+fail_monc:
+       ceph_monc_stop(&client->monc);
+fail_mempool:
+       mempool_destroy(client->wb_pagevec_pool);
+fail_trunc_wq:
+       destroy_workqueue(client->trunc_wq);
+fail_pg_inv_wq:
+       destroy_workqueue(client->pg_inv_wq);
+fail_wb_wq:
+       destroy_workqueue(client->wb_wq);
+fail_bdi:
+       bdi_destroy(&client->backing_dev_info);
+fail:
+       kfree(client);
+       return ERR_PTR(err);
+}
+
+static void ceph_destroy_client(struct ceph_client *client)
+{
+       dout("destroy_client %p\n", client);
+
+       /* unmount */
+       ceph_mdsc_stop(&client->mdsc);
+       ceph_monc_stop(&client->monc);
+       ceph_osdc_stop(&client->osdc);
+
+       ceph_adjust_min_caps(-client->min_caps);
+
+       ceph_debugfs_client_cleanup(client);
+       destroy_workqueue(client->wb_wq);
+       destroy_workqueue(client->pg_inv_wq);
+       destroy_workqueue(client->trunc_wq);
+
+       if (client->msgr)
+               ceph_messenger_destroy(client->msgr);
+       mempool_destroy(client->wb_pagevec_pool);
+
+       destroy_mount_args(client->mount_args);
+
+       kfree(client);
+       dout("destroy_client %p done\n", client);
+}
+
+/*
+ * Initially learn our fsid, or verify an fsid matches.
+ */
+int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
+{
+       if (client->have_fsid) {
+               if (ceph_fsid_compare(&client->fsid, fsid)) {
+                       pr_err("bad fsid, had " FSID_FORMAT " got " FSID_FORMAT,
+                              PR_FSID(&client->fsid), PR_FSID(fsid));
+                       return -1;
+               }
+       } else {
+               pr_info("client%lld fsid " FSID_FORMAT "\n",
+                       client->monc.auth->global_id, PR_FSID(fsid));
+               memcpy(&client->fsid, fsid, sizeof(*fsid));
+               ceph_debugfs_client_init(client);
+               client->have_fsid = true;
+       }
+       return 0;
+}
+
+/*
+ * true if we have the mon map (and have thus joined the cluster)
+ */
+static int have_mon_map(struct ceph_client *client)
+{
+       return client->monc.monmap && client->monc.monmap->epoch;
+}
+
+/*
+ * Bootstrap mount by opening the root directory.  Note the mount
+ * @started time from caller, and time out if this takes too long.
+ */
+static struct dentry *open_root_dentry(struct ceph_client *client,
+                                      const char *path,
+                                      unsigned long started)
+{
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_request *req = NULL;
+       int err;
+       struct dentry *root;
+
+       /* open dir */
+       dout("open_root_inode opening '%s'\n", path);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
+       if (IS_ERR(req))
+               return ERR_PTR(PTR_ERR(req));
+       req->r_path1 = kstrdup(path, GFP_NOFS);
+       req->r_ino1.ino = CEPH_INO_ROOT;
+       req->r_ino1.snap = CEPH_NOSNAP;
+       req->r_started = started;
+       req->r_timeout = client->mount_args->mount_timeout * HZ;
+       req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
+       req->r_num_caps = 2;
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+       if (err == 0) {
+               dout("open_root_inode success\n");
+               if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT &&
+                   client->sb->s_root == NULL)
+                       root = d_alloc_root(req->r_target_inode);
+               else
+                       root = d_obtain_alias(req->r_target_inode);
+               req->r_target_inode = NULL;
+               dout("open_root_inode success, root dentry is %p\n", root);
+       } else {
+               root = ERR_PTR(err);
+       }
+       ceph_mdsc_put_request(req);
+       return root;
+}
+
+/*
+ * mount: join the ceph cluster, and open root directory.
+ */
+static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt,
+                     const char *path)
+{
+       struct ceph_entity_addr *myaddr = NULL;
+       int err;
+       unsigned long timeout = client->mount_args->mount_timeout * HZ;
+       unsigned long started = jiffies;  /* note the start time */
+       struct dentry *root;
+
+       dout("mount start\n");
+       mutex_lock(&client->mount_mutex);
+
+       /* initialize the messenger */
+       if (client->msgr == NULL) {
+               if (ceph_test_opt(client, MYIP))
+                       myaddr = &client->mount_args->my_addr;
+               client->msgr = ceph_messenger_create(myaddr);
+               if (IS_ERR(client->msgr)) {
+                       err = PTR_ERR(client->msgr);
+                       client->msgr = NULL;
+                       goto out;
+               }
+               client->msgr->nocrc = ceph_test_opt(client, NOCRC);
+       }
+
+       /* open session, and wait for mon, mds, and osd maps */
+       err = ceph_monc_open_session(&client->monc);
+       if (err < 0)
+               goto out;
+
+       while (!have_mon_map(client)) {
+               err = -EIO;
+               if (timeout && time_after_eq(jiffies, started + timeout))
+                       goto out;
+
+               /* wait */
+               dout("mount waiting for mon_map\n");
+               err = wait_event_interruptible_timeout(client->auth_wq,
+                              have_mon_map(client) || (client->auth_err < 0),
+                              timeout);
+               if (err == -EINTR || err == -ERESTARTSYS)
+                       goto out;
+               if (client->auth_err < 0) {
+                       err = client->auth_err;
+                       goto out;
+               }
+       }
+
+       dout("mount opening root\n");
+       root = open_root_dentry(client, "", started);
+       if (IS_ERR(root)) {
+               err = PTR_ERR(root);
+               goto out;
+       }
+       if (client->sb->s_root)
+               dput(root);
+       else
+               client->sb->s_root = root;
+
+       if (path[0] == 0) {
+               dget(root);
+       } else {
+               dout("mount opening base mountpoint\n");
+               root = open_root_dentry(client, path, started);
+               if (IS_ERR(root)) {
+                       err = PTR_ERR(root);
+                       dput(client->sb->s_root);
+                       client->sb->s_root = NULL;
+                       goto out;
+               }
+       }
+
+       mnt->mnt_root = root;
+       mnt->mnt_sb = client->sb;
+
+       client->mount_state = CEPH_MOUNT_MOUNTED;
+       dout("mount success\n");
+       err = 0;
+
+out:
+       mutex_unlock(&client->mount_mutex);
+       return err;
+}
+
+static int ceph_set_super(struct super_block *s, void *data)
+{
+       struct ceph_client *client = data;
+       int ret;
+
+       dout("set_super %p data %p\n", s, data);
+
+       s->s_flags = client->mount_args->sb_flags;
+       s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
+
+       s->s_fs_info = client;
+       client->sb = s;
+
+       s->s_op = &ceph_super_ops;
+       s->s_export_op = &ceph_export_ops;
+
+       s->s_time_gran = 1000;  /* 1000 ns == 1 us */
+
+       ret = set_anon_super(s, NULL);  /* what is that second arg for? */
+       if (ret != 0)
+               goto fail;
+
+       return ret;
+
+fail:
+       s->s_fs_info = NULL;
+       client->sb = NULL;
+       return ret;
+}
+
+/*
+ * share superblock if same fs AND options
+ */
+static int ceph_compare_super(struct super_block *sb, void *data)
+{
+       struct ceph_client *new = data;
+       struct ceph_mount_args *args = new->mount_args;
+       struct ceph_client *other = ceph_sb_to_client(sb);
+       int i;
+
+       dout("ceph_compare_super %p\n", sb);
+       if (args->flags & CEPH_OPT_FSID) {
+               if (ceph_fsid_compare(&args->fsid, &other->fsid)) {
+                       dout("fsid doesn't match\n");
+                       return 0;
+               }
+       } else {
+               /* do we share (a) monitor? */
+               for (i = 0; i < new->monc.monmap->num_mon; i++)
+                       if (ceph_monmap_contains(other->monc.monmap,
+                                        &new->monc.monmap->mon_inst[i].addr))
+                               break;
+               if (i == new->monc.monmap->num_mon) {
+                       dout("mon ip not part of monmap\n");
+                       return 0;
+               }
+               dout("mon ip matches existing sb %p\n", sb);
+       }
+       if (args->sb_flags != other->mount_args->sb_flags) {
+               dout("flags differ\n");
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * construct our own bdi so we can control readahead, etc.
+ */
+static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client)
+{
+       int err;
+
+       sb->s_bdi = &client->backing_dev_info;
+
+       /* set ra_pages based on rsize mount option? */
+       if (client->mount_args->rsize >= PAGE_CACHE_SIZE)
+               client->backing_dev_info.ra_pages =
+                       (client->mount_args->rsize + PAGE_CACHE_SIZE - 1)
+                       >> PAGE_SHIFT;
+       err = bdi_register_dev(&client->backing_dev_info, sb->s_dev);
+       return err;
+}
+
+static int ceph_get_sb(struct file_system_type *fs_type,
+                      int flags, const char *dev_name, void *data,
+                      struct vfsmount *mnt)
+{
+       struct super_block *sb;
+       struct ceph_client *client;
+       int err;
+       int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
+       const char *path = NULL;
+       struct ceph_mount_args *args;
+
+       dout("ceph_get_sb\n");
+       args = parse_mount_args(flags, data, dev_name, &path);
+       if (IS_ERR(args)) {
+               err = PTR_ERR(args);
+               goto out_final;
+       }
+
+       /* create client (which we may/may not use) */
+       client = ceph_create_client(args);
+       if (IS_ERR(client)) {
+               err = PTR_ERR(client);
+               goto out_final;
+       }
+
+       if (client->mount_args->flags & CEPH_OPT_NOSHARE)
+               compare_super = NULL;
+       sb = sget(fs_type, compare_super, ceph_set_super, client);
+       if (IS_ERR(sb)) {
+               err = PTR_ERR(sb);
+               goto out;
+       }
+
+       if (ceph_client(sb) != client) {
+               ceph_destroy_client(client);
+               client = ceph_client(sb);
+               dout("get_sb got existing client %p\n", client);
+       } else {
+               dout("get_sb using new client %p\n", client);
+               err = ceph_register_bdi(sb, client);
+               if (err < 0)
+                       goto out_splat;
+       }
+
+       err = ceph_mount(client, mnt, path);
+       if (err < 0)
+               goto out_splat;
+       dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root,
+            mnt->mnt_root->d_inode, ceph_vinop(mnt->mnt_root->d_inode));
+       return 0;
+
+out_splat:
+       ceph_mdsc_close_sessions(&client->mdsc);
+       up_write(&sb->s_umount);
+       deactivate_super(sb);
+       goto out_final;
+
+out:
+       ceph_destroy_client(client);
+out_final:
+       dout("ceph_get_sb fail %d\n", err);
+       return err;
+}
+
+static void ceph_kill_sb(struct super_block *s)
+{
+       struct ceph_client *client = ceph_sb_to_client(s);
+       dout("kill_sb %p\n", s);
+       ceph_mdsc_pre_umount(&client->mdsc);
+       kill_anon_super(s);    /* will call put_super after sb is r/o */
+       if (s->s_bdi == &client->backing_dev_info)
+               bdi_unregister(&client->backing_dev_info);
+       bdi_destroy(&client->backing_dev_info);
+       ceph_destroy_client(client);
+}
+
+static struct file_system_type ceph_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "ceph",
+       .get_sb         = ceph_get_sb,
+       .kill_sb        = ceph_kill_sb,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE,
+};
+
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+
+static int __init init_ceph(void)
+{
+       int ret = 0;
+
+       ret = ceph_debugfs_init();
+       if (ret < 0)
+               goto out;
+
+       ret = ceph_msgr_init();
+       if (ret < 0)
+               goto out_debugfs;
+
+       ret = init_caches();
+       if (ret)
+               goto out_msgr;
+
+       ceph_caps_init();
+
+       ret = register_filesystem(&ceph_fs_type);
+       if (ret)
+               goto out_icache;
+
+       pr_info("loaded %d.%d.%d (mon/mds/osd proto %d/%d/%d)\n",
+               CEPH_VERSION_MAJOR, CEPH_VERSION_MINOR, CEPH_VERSION_PATCH,
+               CEPH_MONC_PROTOCOL, CEPH_MDSC_PROTOCOL, CEPH_OSDC_PROTOCOL);
+       return 0;
+
+out_icache:
+       destroy_caches();
+out_msgr:
+       ceph_msgr_exit();
+out_debugfs:
+       ceph_debugfs_cleanup();
+out:
+       return ret;
+}
+
+static void __exit exit_ceph(void)
+{
+       dout("exit_ceph\n");
+       unregister_filesystem(&ceph_fs_type);
+       ceph_caps_finalize();
+       destroy_caches();
+       ceph_msgr_exit();
+       ceph_debugfs_cleanup();
+}
+
+module_init(init_ceph);
+module_exit(exit_ceph);
+
+MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
+MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
+MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
+MODULE_DESCRIPTION("Ceph filesystem for Linux");
+MODULE_LICENSE("GPL");
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
new file mode 100644 (file)
index 0000000..65d1203
--- /dev/null
@@ -0,0 +1,901 @@
+#ifndef _FS_CEPH_SUPER_H
+#define _FS_CEPH_SUPER_H
+
+#include "ceph_debug.h"
+
+#include <asm/unaligned.h>
+#include <linux/backing-dev.h>
+#include <linux/completion.h>
+#include <linux/exportfs.h>
+#include <linux/fs.h>
+#include <linux/mempool.h>
+#include <linux/pagemap.h>
+#include <linux/wait.h>
+#include <linux/writeback.h>
+
+#include "types.h"
+#include "messenger.h"
+#include "msgpool.h"
+#include "mon_client.h"
+#include "mds_client.h"
+#include "osd_client.h"
+#include "ceph_fs.h"
+
+/* f_type in struct statfs */
+#define CEPH_SUPER_MAGIC 0x00c36400
+
+/* large granularity for statfs utilization stats to facilitate
+ * large volume sizes on 32-bit machines. */
+#define CEPH_BLOCK_SHIFT   20  /* 1 MB */
+#define CEPH_BLOCK         (1 << CEPH_BLOCK_SHIFT)
+
+/*
+ * mount options
+ */
+#define CEPH_OPT_FSID             (1<<0)
+#define CEPH_OPT_NOSHARE          (1<<1) /* don't share client with other sbs */
+#define CEPH_OPT_MYIP             (1<<2) /* specified my ip */
+#define CEPH_OPT_DIRSTAT          (1<<4) /* funky `cat dirname` for stats */
+#define CEPH_OPT_RBYTES           (1<<5) /* dir st_bytes = rbytes */
+#define CEPH_OPT_NOCRC            (1<<6) /* no data crc on writes */
+#define CEPH_OPT_NOASYNCREADDIR   (1<<7) /* no dcache readdir */
+
+#define CEPH_OPT_DEFAULT   (CEPH_OPT_RBYTES)
+
+#define ceph_set_opt(client, opt) \
+       (client)->mount_args->flags |= CEPH_OPT_##opt;
+#define ceph_test_opt(client, opt) \
+       (!!((client)->mount_args->flags & CEPH_OPT_##opt))
+
+
+struct ceph_mount_args {
+       int sb_flags;
+       int num_mon;
+       struct ceph_entity_addr *mon_addr;
+       int flags;
+       int mount_timeout;
+       int osd_idle_ttl;
+       int caps_wanted_delay_min, caps_wanted_delay_max;
+       struct ceph_fsid fsid;
+       struct ceph_entity_addr my_addr;
+       int wsize;
+       int rsize;            /* max readahead */
+       int max_readdir;      /* max readdir size */
+       int congestion_kb;      /* max readdir size */
+       int osd_timeout;
+       int osd_keepalive_timeout;
+       char *snapdir_name;   /* default ".snap" */
+       char *name;
+       char *secret;
+       int cap_release_safety;
+};
+
+/*
+ * defaults
+ */
+#define CEPH_MOUNT_TIMEOUT_DEFAULT  60
+#define CEPH_OSD_TIMEOUT_DEFAULT    60  /* seconds */
+#define CEPH_OSD_KEEPALIVE_DEFAULT  5
+#define CEPH_OSD_IDLE_TTL_DEFAULT    60
+#define CEPH_MOUNT_RSIZE_DEFAULT    (512*1024) /* readahead */
+
+#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
+#define CEPH_MSG_MAX_DATA_LEN  (16*1024*1024)
+
+#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
+#define CEPH_AUTH_NAME_DEFAULT   "guest"
+
+/*
+ * Delay telling the MDS we no longer want caps, in case we reopen
+ * the file.  Delay a minimum amount of time, even if we send a cap
+ * message for some other reason.  Otherwise, take the oppotunity to
+ * update the mds to avoid sending another message later.
+ */
+#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT      5  /* cap release delay */
+#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT     60  /* cap release delay */
+
+
+/* mount state */
+enum {
+       CEPH_MOUNT_MOUNTING,
+       CEPH_MOUNT_MOUNTED,
+       CEPH_MOUNT_UNMOUNTING,
+       CEPH_MOUNT_UNMOUNTED,
+       CEPH_MOUNT_SHUTDOWN,
+};
+
+/*
+ * subtract jiffies
+ */
+static inline unsigned long time_sub(unsigned long a, unsigned long b)
+{
+       BUG_ON(time_after(b, a));
+       return (long)a - (long)b;
+}
+
+/*
+ * per-filesystem client state
+ *
+ * possibly shared by multiple mount points, if they are
+ * mounting the same ceph filesystem/cluster.
+ */
+struct ceph_client {
+       struct ceph_fsid fsid;
+       bool have_fsid;
+
+       struct mutex mount_mutex;       /* serialize mount attempts */
+       struct ceph_mount_args *mount_args;
+
+       struct super_block *sb;
+
+       unsigned long mount_state;
+       wait_queue_head_t auth_wq;
+
+       int auth_err;
+
+       int min_caps;                  /* min caps i added */
+
+       struct ceph_messenger *msgr;   /* messenger instance */
+       struct ceph_mon_client monc;
+       struct ceph_mds_client mdsc;
+       struct ceph_osd_client osdc;
+
+       /* writeback */
+       mempool_t *wb_pagevec_pool;
+       struct workqueue_struct *wb_wq;
+       struct workqueue_struct *pg_inv_wq;
+       struct workqueue_struct *trunc_wq;
+       atomic_long_t writeback_count;
+
+       struct backing_dev_info backing_dev_info;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_monmap;
+       struct dentry *debugfs_mdsmap, *debugfs_osdmap;
+       struct dentry *debugfs_dir, *debugfs_dentry_lru, *debugfs_caps;
+       struct dentry *debugfs_congestion_kb;
+       struct dentry *debugfs_bdi;
+#endif
+};
+
+static inline struct ceph_client *ceph_client(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
+
+/*
+ * File i/o capability.  This tracks shared state with the metadata
+ * server that allows us to cache or writeback attributes or to read
+ * and write data.  For any given inode, we should have one or more
+ * capabilities, one issued by each metadata server, and our
+ * cumulative access is the OR of all issued capabilities.
+ *
+ * Each cap is referenced by the inode's i_caps rbtree and by per-mds
+ * session capability lists.
+ */
+struct ceph_cap {
+       struct ceph_inode_info *ci;
+       struct rb_node ci_node;          /* per-ci cap tree */
+       struct ceph_mds_session *session;
+       struct list_head session_caps;   /* per-session caplist */
+       int mds;
+       u64 cap_id;       /* unique cap id (mds provided) */
+       int issued;       /* latest, from the mds */
+       int implemented;  /* implemented superset of issued (for revocation) */
+       int mds_wanted;
+       u32 seq, issue_seq, mseq;
+       u32 cap_gen;      /* active/stale cycle */
+       unsigned long last_used;
+       struct list_head caps_item;
+};
+
+#define CHECK_CAPS_NODELAY    1  /* do not delay any further */
+#define CHECK_CAPS_AUTHONLY   2  /* only check auth cap */
+#define CHECK_CAPS_FLUSH      4  /* flush any dirty caps */
+
+/*
+ * Snapped cap state that is pending flush to mds.  When a snapshot occurs,
+ * we first complete any in-process sync writes and writeback any dirty
+ * data before flushing the snapped state (tracked here) back to the MDS.
+ */
+struct ceph_cap_snap {
+       atomic_t nref;
+       struct ceph_inode_info *ci;
+       struct list_head ci_item, flushing_item;
+
+       u64 follows, flush_tid;
+       int issued, dirty;
+       struct ceph_snap_context *context;
+
+       mode_t mode;
+       uid_t uid;
+       gid_t gid;
+
+       void *xattr_blob;
+       int xattr_len;
+       u64 xattr_version;
+
+       u64 size;
+       struct timespec mtime, atime, ctime;
+       u64 time_warp_seq;
+       int writing;   /* a sync write is still in progress */
+       int dirty_pages;     /* dirty pages awaiting writeback */
+};
+
+static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
+{
+       if (atomic_dec_and_test(&capsnap->nref))
+               kfree(capsnap);
+}
+
+/*
+ * The frag tree describes how a directory is fragmented, potentially across
+ * multiple metadata servers.  It is also used to indicate points where
+ * metadata authority is delegated, and whether/where metadata is replicated.
+ *
+ * A _leaf_ frag will be present in the i_fragtree IFF there is
+ * delegation info.  That is, if mds >= 0 || ndist > 0.
+ */
+#define CEPH_MAX_DIRFRAG_REP 4
+
+struct ceph_inode_frag {
+       struct rb_node node;
+
+       /* fragtree state */
+       u32 frag;
+       int split_by;         /* i.e. 2^(split_by) children */
+
+       /* delegation and replication info */
+       int mds;              /* -1 if same authority as parent */
+       int ndist;            /* >0 if replicated */
+       int dist[CEPH_MAX_DIRFRAG_REP];
+};
+
+/*
+ * We cache inode xattrs as an encoded blob until they are first used,
+ * at which point we parse them into an rbtree.
+ */
+struct ceph_inode_xattr {
+       struct rb_node node;
+
+       const char *name;
+       int name_len;
+       const char *val;
+       int val_len;
+       int dirty;
+
+       int should_free_name;
+       int should_free_val;
+};
+
+struct ceph_inode_xattrs_info {
+       /*
+        * (still encoded) xattr blob. we avoid the overhead of parsing
+        * this until someone actually calls getxattr, etc.
+        *
+        * blob->vec.iov_len == 4 implies there are no xattrs; blob ==
+        * NULL means we don't know.
+       */
+       struct ceph_buffer *blob, *prealloc_blob;
+
+       struct rb_root index;
+       bool dirty;
+       int count;
+       int names_size;
+       int vals_size;
+       u64 version, index_version;
+};
+
+/*
+ * Ceph inode.
+ */
+#define CEPH_I_COMPLETE  1  /* we have complete directory cached */
+#define CEPH_I_NODELAY   4  /* do not delay cap release */
+#define CEPH_I_FLUSH     8  /* do not delay flush of dirty metadata */
+#define CEPH_I_NOFLUSH  16  /* do not flush dirty caps */
+
+struct ceph_inode_info {
+       struct ceph_vino i_vino;   /* ceph ino + snap */
+
+       u64 i_version;
+       u32 i_time_warp_seq;
+
+       unsigned i_ceph_flags;
+       unsigned long i_release_count;
+
+       struct ceph_file_layout i_layout;
+       char *i_symlink;
+
+       /* for dirs */
+       struct timespec i_rctime;
+       u64 i_rbytes, i_rfiles, i_rsubdirs;
+       u64 i_files, i_subdirs;
+       u64 i_max_offset;  /* largest readdir offset, set with I_COMPLETE */
+
+       struct rb_root i_fragtree;
+       struct mutex i_fragtree_mutex;
+
+       struct ceph_inode_xattrs_info i_xattrs;
+
+       /* capabilities.  protected _both_ by i_lock and cap->session's
+        * s_mutex. */
+       struct rb_root i_caps;           /* cap list */
+       struct ceph_cap *i_auth_cap;     /* authoritative cap, if any */
+       unsigned i_dirty_caps, i_flushing_caps;     /* mask of dirtied fields */
+       struct list_head i_dirty_item, i_flushing_item;
+       u64 i_cap_flush_seq;
+       /* we need to track cap writeback on a per-cap-bit basis, to allow
+        * overlapping, pipelined cap flushes to the mds.  we can probably
+        * reduce the tid to 8 bits if we're concerned about inode size. */
+       u16 i_cap_flush_last_tid, i_cap_flush_tid[CEPH_CAP_BITS];
+       wait_queue_head_t i_cap_wq;      /* threads waiting on a capability */
+       unsigned long i_hold_caps_min; /* jiffies */
+       unsigned long i_hold_caps_max; /* jiffies */
+       struct list_head i_cap_delay_list;  /* for delayed cap release to mds */
+       int i_cap_exporting_mds;         /* to handle cap migration between */
+       unsigned i_cap_exporting_mseq;   /*  mds's. */
+       unsigned i_cap_exporting_issued;
+       struct ceph_cap_reservation i_cap_migration_resv;
+       struct list_head i_cap_snaps;   /* snapped state pending flush to mds */
+       struct ceph_snap_context *i_head_snapc;  /* set if wr_buffer_head > 0 */
+       unsigned i_snap_caps;           /* cap bits for snapped files */
+
+       int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */
+
+       u32 i_truncate_seq;        /* last truncate to smaller size */
+       u64 i_truncate_size;       /*  and the size we last truncated down to */
+       int i_truncate_pending;    /*  still need to call vmtruncate */
+
+       u64 i_max_size;            /* max file size authorized by mds */
+       u64 i_reported_size; /* (max_)size reported to or requested of mds */
+       u64 i_wanted_max_size;     /* offset we'd like to write too */
+       u64 i_requested_max_size;  /* max_size we've requested */
+
+       /* held references to caps */
+       int i_pin_ref;
+       int i_rd_ref, i_rdcache_ref, i_wr_ref;
+       int i_wrbuffer_ref, i_wrbuffer_ref_head;
+       u32 i_shared_gen;       /* increment each time we get FILE_SHARED */
+       u32 i_rdcache_gen;      /* we increment this each time we get
+                                  FILE_CACHE.  If it's non-zero, we
+                                  _may_ have cached pages. */
+       u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
+
+       struct list_head i_unsafe_writes; /* uncommitted sync writes */
+       struct list_head i_unsafe_dirops; /* uncommitted mds dir ops */
+       spinlock_t i_unsafe_lock;
+
+       struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */
+       int i_snap_realm_counter; /* snap realm (if caps) */
+       struct list_head i_snap_realm_item;
+       struct list_head i_snap_flush_item;
+
+       struct work_struct i_wb_work;  /* writeback work */
+       struct work_struct i_pg_inv_work;  /* page invalidation work */
+
+       struct work_struct i_vmtruncate_work;
+
+       struct inode vfs_inode; /* at end */
+};
+
+static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
+{
+       return container_of(inode, struct ceph_inode_info, vfs_inode);
+}
+
+static inline void ceph_i_clear(struct inode *inode, unsigned mask)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       spin_lock(&inode->i_lock);
+       ci->i_ceph_flags &= ~mask;
+       spin_unlock(&inode->i_lock);
+}
+
+static inline void ceph_i_set(struct inode *inode, unsigned mask)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       spin_lock(&inode->i_lock);
+       ci->i_ceph_flags |= mask;
+       spin_unlock(&inode->i_lock);
+}
+
+static inline bool ceph_i_test(struct inode *inode, unsigned mask)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       bool r;
+
+       smp_mb();
+       r = (ci->i_ceph_flags & mask) == mask;
+       return r;
+}
+
+
+/* find a specific frag @f */
+extern struct ceph_inode_frag *__ceph_find_frag(struct ceph_inode_info *ci,
+                                               u32 f);
+
+/*
+ * choose fragment for value @v.  copy frag content to pfrag, if leaf
+ * exists
+ */
+extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
+                           struct ceph_inode_frag *pfrag,
+                           int *found);
+
+/*
+ * Ceph dentry state
+ */
+struct ceph_dentry_info {
+       struct ceph_mds_session *lease_session;
+       u32 lease_gen, lease_shared_gen;
+       u32 lease_seq;
+       unsigned long lease_renew_after, lease_renew_from;
+       struct list_head lru;
+       struct dentry *dentry;
+       u64 time;
+       u64 offset;
+};
+
+static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry)
+{
+       return (struct ceph_dentry_info *)dentry->d_fsdata;
+}
+
+static inline loff_t ceph_make_fpos(unsigned frag, unsigned off)
+{
+       return ((loff_t)frag << 32) | (loff_t)off;
+}
+
+/*
+ * ino_t is <64 bits on many architectures, blech.
+ *
+ * don't include snap in ino hash, at least for now.
+ */
+static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
+{
+       ino_t ino = (ino_t)vino.ino;  /* ^ (vino.snap << 20); */
+#if BITS_PER_LONG == 32
+       ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
+       if (!ino)
+               ino = 1;
+#endif
+       return ino;
+}
+
+static inline int ceph_set_ino_cb(struct inode *inode, void *data)
+{
+       ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
+       inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
+       return 0;
+}
+
+static inline struct ceph_vino ceph_vino(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino;
+}
+
+/* for printf-style formatting */
+#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
+
+static inline u64 ceph_ino(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino.ino;
+}
+static inline u64 ceph_snap(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino.snap;
+}
+
+static inline int ceph_ino_compare(struct inode *inode, void *data)
+{
+       struct ceph_vino *pvino = (struct ceph_vino *)data;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       return ci->i_vino.ino == pvino->ino &&
+               ci->i_vino.snap == pvino->snap;
+}
+
+static inline struct inode *ceph_find_inode(struct super_block *sb,
+                                           struct ceph_vino vino)
+{
+       ino_t t = ceph_vino_to_ino(vino);
+       return ilookup5(sb, t, ceph_ino_compare, &vino);
+}
+
+
+/*
+ * caps helpers
+ */
+static inline bool __ceph_is_any_real_caps(struct ceph_inode_info *ci)
+{
+       return !RB_EMPTY_ROOT(&ci->i_caps);
+}
+
+extern int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented);
+extern int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int t);
+extern int __ceph_caps_issued_other(struct ceph_inode_info *ci,
+                                   struct ceph_cap *cap);
+
+static inline int ceph_caps_issued(struct ceph_inode_info *ci)
+{
+       int issued;
+       spin_lock(&ci->vfs_inode.i_lock);
+       issued = __ceph_caps_issued(ci, NULL);
+       spin_unlock(&ci->vfs_inode.i_lock);
+       return issued;
+}
+
+static inline int ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask,
+                                       int touch)
+{
+       int r;
+       spin_lock(&ci->vfs_inode.i_lock);
+       r = __ceph_caps_issued_mask(ci, mask, touch);
+       spin_unlock(&ci->vfs_inode.i_lock);
+       return r;
+}
+
+static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)
+{
+       return ci->i_dirty_caps | ci->i_flushing_caps;
+}
+extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
+
+extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
+extern int __ceph_caps_used(struct ceph_inode_info *ci);
+
+extern int __ceph_caps_file_wanted(struct ceph_inode_info *ci);
+
+/*
+ * wanted, by virtue of open file modes AND cap refs (buffered/cached data)
+ */
+static inline int __ceph_caps_wanted(struct ceph_inode_info *ci)
+{
+       int w = __ceph_caps_file_wanted(ci) | __ceph_caps_used(ci);
+       if (w & CEPH_CAP_FILE_BUFFER)
+               w |= CEPH_CAP_FILE_EXCL;  /* we want EXCL if dirty data */
+       return w;
+}
+
+/* what the mds thinks we want */
+extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci);
+
+extern void ceph_caps_init(void);
+extern void ceph_caps_finalize(void);
+extern void ceph_adjust_min_caps(int delta);
+extern int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need);
+extern int ceph_unreserve_caps(struct ceph_cap_reservation *ctx);
+extern void ceph_reservation_status(struct ceph_client *client,
+                                   int *total, int *avail, int *used,
+                                   int *reserved, int *min);
+
+static inline struct ceph_client *ceph_inode_to_client(struct inode *inode)
+{
+       return (struct ceph_client *)inode->i_sb->s_fs_info;
+}
+
+static inline struct ceph_client *ceph_sb_to_client(struct super_block *sb)
+{
+       return (struct ceph_client *)sb->s_fs_info;
+}
+
+
+/*
+ * we keep buffered readdir results attached to file->private_data
+ */
+struct ceph_file_info {
+       int fmode;     /* initialized on open */
+
+       /* readdir: position within the dir */
+       u32 frag;
+       struct ceph_mds_request *last_readdir;
+       int at_end;
+
+       /* readdir: position within a frag */
+       unsigned offset;       /* offset of last chunk, adjusted for . and .. */
+       u64 next_offset;       /* offset of next chunk (last_name's + 1) */
+       char *last_name;       /* last entry in previous chunk */
+       struct dentry *dentry; /* next dentry (for dcache readdir) */
+       unsigned long dir_release_count;
+
+       /* used for -o dirstat read() on directory thing */
+       char *dir_info;
+       int dir_info_len;
+};
+
+
+
+/*
+ * snapshots
+ */
+
+/*
+ * A "snap context" is the set of existing snapshots when we
+ * write data.  It is used by the OSD to guide its COW behavior.
+ *
+ * The ceph_snap_context is refcounted, and attached to each dirty
+ * page, indicating which context the dirty data belonged when it was
+ * dirtied.
+ */
+struct ceph_snap_context {
+       atomic_t nref;
+       u64 seq;
+       int num_snaps;
+       u64 snaps[];
+};
+
+static inline struct ceph_snap_context *
+ceph_get_snap_context(struct ceph_snap_context *sc)
+{
+       /*
+       printk("get_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+              atomic_read(&sc->nref)+1);
+       */
+       if (sc)
+               atomic_inc(&sc->nref);
+       return sc;
+}
+
+static inline void ceph_put_snap_context(struct ceph_snap_context *sc)
+{
+       if (!sc)
+               return;
+       /*
+       printk("put_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+              atomic_read(&sc->nref)-1);
+       */
+       if (atomic_dec_and_test(&sc->nref)) {
+               /*printk(" deleting snap_context %p\n", sc);*/
+               kfree(sc);
+       }
+}
+
+/*
+ * A "snap realm" describes a subset of the file hierarchy sharing
+ * the same set of snapshots that apply to it.  The realms themselves
+ * are organized into a hierarchy, such that children inherit (some of)
+ * the snapshots of their parents.
+ *
+ * All inodes within the realm that have capabilities are linked into a
+ * per-realm list.
+ */
+struct ceph_snap_realm {
+       u64 ino;
+       atomic_t nref;
+       struct rb_node node;
+
+       u64 created, seq;
+       u64 parent_ino;
+       u64 parent_since;   /* snapid when our current parent became so */
+
+       u64 *prior_parent_snaps;      /* snaps inherited from any parents we */
+       int num_prior_parent_snaps;   /*  had prior to parent_since */
+       u64 *snaps;                   /* snaps specific to this realm */
+       int num_snaps;
+
+       struct ceph_snap_realm *parent;
+       struct list_head children;       /* list of child realms */
+       struct list_head child_item;
+
+       struct list_head empty_item;     /* if i have ref==0 */
+
+       /* the current set of snaps for this realm */
+       struct ceph_snap_context *cached_context;
+
+       struct list_head inodes_with_caps;
+       spinlock_t inodes_with_caps_lock;
+};
+
+
+
+/*
+ * calculate the number of pages a given length and offset map onto,
+ * if we align the data.
+ */
+static inline int calc_pages_for(u64 off, u64 len)
+{
+       return ((off+len+PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT) -
+               (off >> PAGE_CACHE_SHIFT);
+}
+
+
+
+/* snap.c */
+struct ceph_snap_realm *ceph_lookup_snap_realm(struct ceph_mds_client *mdsc,
+                                              u64 ino);
+extern void ceph_get_snap_realm(struct ceph_mds_client *mdsc,
+                               struct ceph_snap_realm *realm);
+extern void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
+                               struct ceph_snap_realm *realm);
+extern int ceph_update_snap_trace(struct ceph_mds_client *m,
+                                 void *p, void *e, bool deletion);
+extern void ceph_handle_snap(struct ceph_mds_client *mdsc,
+                            struct ceph_mds_session *session,
+                            struct ceph_msg *msg);
+extern void ceph_queue_cap_snap(struct ceph_inode_info *ci,
+                               struct ceph_snap_context *snapc);
+extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
+                                 struct ceph_cap_snap *capsnap);
+extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc);
+
+/*
+ * a cap_snap is "pending" if it is still awaiting an in-progress
+ * sync write (that may/may not still update size, mtime, etc.).
+ */
+static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
+{
+       return !list_empty(&ci->i_cap_snaps) &&
+               list_entry(ci->i_cap_snaps.prev, struct ceph_cap_snap,
+                          ci_item)->writing;
+}
+
+
+/* super.c */
+extern struct kmem_cache *ceph_inode_cachep;
+extern struct kmem_cache *ceph_cap_cachep;
+extern struct kmem_cache *ceph_dentry_cachep;
+extern struct kmem_cache *ceph_file_cachep;
+
+extern const char *ceph_msg_type_name(int type);
+extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
+
+#define FSID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+       "%02x%02x%02x%02x%02x%02x"
+#define PR_FSID(f) (f)->fsid[0], (f)->fsid[1], (f)->fsid[2], (f)->fsid[3], \
+               (f)->fsid[4], (f)->fsid[5], (f)->fsid[6], (f)->fsid[7],    \
+               (f)->fsid[8], (f)->fsid[9], (f)->fsid[10], (f)->fsid[11],  \
+               (f)->fsid[12], (f)->fsid[13], (f)->fsid[14], (f)->fsid[15]
+
+/* inode.c */
+extern const struct inode_operations ceph_file_iops;
+
+extern struct inode *ceph_alloc_inode(struct super_block *sb);
+extern void ceph_destroy_inode(struct inode *inode);
+
+extern struct inode *ceph_get_inode(struct super_block *sb,
+                                   struct ceph_vino vino);
+extern struct inode *ceph_get_snapdir(struct inode *parent);
+extern int ceph_fill_file_size(struct inode *inode, int issued,
+                              u32 truncate_seq, u64 truncate_size, u64 size);
+extern void ceph_fill_file_time(struct inode *inode, int issued,
+                               u64 time_warp_seq, struct timespec *ctime,
+                               struct timespec *mtime, struct timespec *atime);
+extern int ceph_fill_trace(struct super_block *sb,
+                          struct ceph_mds_request *req,
+                          struct ceph_mds_session *session);
+extern int ceph_readdir_prepopulate(struct ceph_mds_request *req,
+                                   struct ceph_mds_session *session);
+
+extern int ceph_inode_holds_cap(struct inode *inode, int mask);
+
+extern int ceph_inode_set_size(struct inode *inode, loff_t size);
+extern void __ceph_do_pending_vmtruncate(struct inode *inode);
+extern void ceph_queue_vmtruncate(struct inode *inode);
+
+extern void ceph_queue_invalidate(struct inode *inode);
+extern void ceph_queue_writeback(struct inode *inode);
+
+extern int ceph_do_getattr(struct inode *inode, int mask);
+extern int ceph_permission(struct inode *inode, int mask);
+extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
+extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
+                       struct kstat *stat);
+
+/* xattr.c */
+extern int ceph_setxattr(struct dentry *, const char *, const void *,
+                        size_t, int);
+extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
+extern int ceph_removexattr(struct dentry *, const char *);
+extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
+extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
+
+/* caps.c */
+extern const char *ceph_cap_string(int c);
+extern void ceph_handle_caps(struct ceph_mds_session *session,
+                            struct ceph_msg *msg);
+extern int ceph_add_cap(struct inode *inode,
+                       struct ceph_mds_session *session, u64 cap_id,
+                       int fmode, unsigned issued, unsigned wanted,
+                       unsigned cap, unsigned seq, u64 realmino, int flags,
+                       struct ceph_cap_reservation *caps_reservation);
+extern void __ceph_remove_cap(struct ceph_cap *cap);
+static inline void ceph_remove_cap(struct ceph_cap *cap)
+{
+       struct inode *inode = &cap->ci->vfs_inode;
+       spin_lock(&inode->i_lock);
+       __ceph_remove_cap(cap);
+       spin_unlock(&inode->i_lock);
+}
+extern void ceph_put_cap(struct ceph_cap *cap);
+
+extern void ceph_queue_caps_release(struct inode *inode);
+extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc);
+extern int ceph_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
+                                   struct ceph_mds_session *session);
+extern int ceph_get_cap_mds(struct inode *inode);
+extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps);
+extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);
+extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
+                                      struct ceph_snap_context *snapc);
+extern void __ceph_flush_snaps(struct ceph_inode_info *ci,
+                              struct ceph_mds_session **psession);
+extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
+                           struct ceph_mds_session *session);
+extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
+extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);
+
+extern int ceph_encode_inode_release(void **p, struct inode *inode,
+                                    int mds, int drop, int unless, int force);
+extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
+                                     int mds, int drop, int unless);
+
+extern int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
+                        int *got, loff_t endoff);
+
+/* for counting open files by mode */
+static inline void __ceph_get_fmode(struct ceph_inode_info *ci, int mode)
+{
+       ci->i_nr_by_mode[mode]++;
+}
+extern void ceph_put_fmode(struct ceph_inode_info *ci, int mode);
+
+/* addr.c */
+extern const struct address_space_operations ceph_aops;
+extern int ceph_mmap(struct file *file, struct vm_area_struct *vma);
+
+/* file.c */
+extern const struct file_operations ceph_file_fops;
+extern const struct address_space_operations ceph_aops;
+extern int ceph_open(struct inode *inode, struct file *file);
+extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+                                      struct nameidata *nd, int mode,
+                                      int locked_dir);
+extern int ceph_release(struct inode *inode, struct file *filp);
+extern void ceph_release_page_vector(struct page **pages, int num_pages);
+
+/* dir.c */
+extern const struct file_operations ceph_dir_fops;
+extern const struct inode_operations ceph_dir_iops;
+extern struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops,
+       ceph_snapdir_dentry_ops;
+
+extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry);
+extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
+                                        struct dentry *dentry, int err);
+
+extern void ceph_dentry_lru_add(struct dentry *dn);
+extern void ceph_dentry_lru_touch(struct dentry *dn);
+extern void ceph_dentry_lru_del(struct dentry *dn);
+
+/*
+ * our d_ops vary depending on whether the inode is live,
+ * snapshotted (read-only), or a virtual ".snap" directory.
+ */
+int ceph_init_dentry(struct dentry *dentry);
+
+
+/* ioctl.c */
+extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+/* export.c */
+extern const struct export_operations ceph_export_ops;
+
+/* debugfs.c */
+extern int ceph_debugfs_init(void);
+extern void ceph_debugfs_cleanup(void);
+extern int ceph_debugfs_client_init(struct ceph_client *client);
+extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
+
+static inline struct inode *get_dentry_parent_inode(struct dentry *dentry)
+{
+       if (dentry && dentry->d_parent)
+               return dentry->d_parent->d_inode;
+
+       return NULL;
+}
+
+#endif /* _FS_CEPH_SUPER_H */
diff --git a/fs/ceph/types.h b/fs/ceph/types.h
new file mode 100644 (file)
index 0000000..28b35a0
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _FS_CEPH_TYPES_H
+#define _FS_CEPH_TYPES_H
+
+/* needed before including ceph_fs.h */
+#include <linux/in.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+
+#include "ceph_fs.h"
+#include "ceph_frag.h"
+#include "ceph_hash.h"
+
+/*
+ * Identify inodes by both their ino AND snapshot id (a u64).
+ */
+struct ceph_vino {
+       u64 ino;
+       u64 snap;
+};
+
+
+/* context for the caps reservation mechanism */
+struct ceph_cap_reservation {
+       int count;
+};
+
+
+#endif
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
new file mode 100644 (file)
index 0000000..37d6ce6
--- /dev/null
@@ -0,0 +1,844 @@
+#include "ceph_debug.h"
+#include "super.h"
+#include "decode.h"
+
+#include <linux/xattr.h>
+
+static bool ceph_is_valid_xattr(const char *name)
+{
+       return !strncmp(name, XATTR_SECURITY_PREFIX,
+                       XATTR_SECURITY_PREFIX_LEN) ||
+              !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
+              !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+}
+
+/*
+ * These define virtual xattrs exposing the recursive directory
+ * statistics and layout metadata.
+ */
+struct ceph_vxattr_cb {
+       bool readonly;
+       char *name;
+       size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
+                             size_t size);
+};
+
+/* directories */
+
+static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
+}
+
+static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
+                                     size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_files);
+}
+
+static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_subdirs);
+}
+
+static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
+                                        size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
+}
+
+static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
+                                      size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_rfiles);
+}
+
+static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
+                                        size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_rsubdirs);
+}
+
+static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
+                                      size_t size)
+{
+       return snprintf(val, size, "%lld", ci->i_rbytes);
+}
+
+static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
+                                      size_t size)
+{
+       return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
+                       (long)ci->i_rctime.tv_nsec);
+}
+
+static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
+       { true, "user.ceph.dir.entries", ceph_vxattrcb_entries},
+       { true, "user.ceph.dir.files", ceph_vxattrcb_files},
+       { true, "user.ceph.dir.subdirs", ceph_vxattrcb_subdirs},
+       { true, "user.ceph.dir.rentries", ceph_vxattrcb_rentries},
+       { true, "user.ceph.dir.rfiles", ceph_vxattrcb_rfiles},
+       { true, "user.ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
+       { true, "user.ceph.dir.rbytes", ceph_vxattrcb_rbytes},
+       { true, "user.ceph.dir.rctime", ceph_vxattrcb_rctime},
+       { true, NULL, NULL }
+};
+
+/* files */
+
+static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
+                                  size_t size)
+{
+       int ret;
+
+       ret = snprintf(val, size,
+               "chunk_bytes=%lld\nstripe_count=%lld\nobject_size=%lld\n",
+               (unsigned long long)ceph_file_layout_su(ci->i_layout),
+               (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
+               (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
+       if (ceph_file_layout_pg_preferred(ci->i_layout))
+               ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
+                           (unsigned long long)ceph_file_layout_pg_preferred(
+                                   ci->i_layout));
+       return ret;
+}
+
+static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
+       { true, "user.ceph.layout", ceph_vxattrcb_layout},
+       { NULL, NULL }
+};
+
+static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
+{
+       if (S_ISDIR(inode->i_mode))
+               return ceph_dir_vxattrs;
+       else if (S_ISREG(inode->i_mode))
+               return ceph_file_vxattrs;
+       return NULL;
+}
+
+static struct ceph_vxattr_cb *ceph_match_vxattr(struct ceph_vxattr_cb *vxattr,
+                                               const char *name)
+{
+       do {
+               if (strcmp(vxattr->name, name) == 0)
+                       return vxattr;
+               vxattr++;
+       } while (vxattr->name);
+       return NULL;
+}
+
+static int __set_xattr(struct ceph_inode_info *ci,
+                          const char *name, int name_len,
+                          const char *val, int val_len,
+                          int dirty,
+                          int should_free_name, int should_free_val,
+                          struct ceph_inode_xattr **newxattr)
+{
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+       struct ceph_inode_xattr *xattr = NULL;
+       int c;
+       int new = 0;
+
+       p = &ci->i_xattrs.index.rb_node;
+       while (*p) {
+               parent = *p;
+               xattr = rb_entry(parent, struct ceph_inode_xattr, node);
+               c = strncmp(name, xattr->name, min(name_len, xattr->name_len));
+               if (c < 0)
+                       p = &(*p)->rb_left;
+               else if (c > 0)
+                       p = &(*p)->rb_right;
+               else {
+                       if (name_len == xattr->name_len)
+                               break;
+                       else if (name_len < xattr->name_len)
+                               p = &(*p)->rb_left;
+                       else
+                               p = &(*p)->rb_right;
+               }
+               xattr = NULL;
+       }
+
+       if (!xattr) {
+               new = 1;
+               xattr = *newxattr;
+               xattr->name = name;
+               xattr->name_len = name_len;
+               xattr->should_free_name = should_free_name;
+
+               ci->i_xattrs.count++;
+               dout("__set_xattr count=%d\n", ci->i_xattrs.count);
+       } else {
+               kfree(*newxattr);
+               *newxattr = NULL;
+               if (xattr->should_free_val)
+                       kfree((void *)xattr->val);
+
+               if (should_free_name) {
+                       kfree((void *)name);
+                       name = xattr->name;
+               }
+               ci->i_xattrs.names_size -= xattr->name_len;
+               ci->i_xattrs.vals_size -= xattr->val_len;
+       }
+       if (!xattr) {
+               pr_err("__set_xattr ENOMEM on %p %llx.%llx xattr %s=%s\n",
+                      &ci->vfs_inode, ceph_vinop(&ci->vfs_inode), name,
+                      xattr->val);
+               return -ENOMEM;
+       }
+       ci->i_xattrs.names_size += name_len;
+       ci->i_xattrs.vals_size += val_len;
+       if (val)
+               xattr->val = val;
+       else
+               xattr->val = "";
+
+       xattr->val_len = val_len;
+       xattr->dirty = dirty;
+       xattr->should_free_val = (val && should_free_val);
+
+       if (new) {
+               rb_link_node(&xattr->node, parent, p);
+               rb_insert_color(&xattr->node, &ci->i_xattrs.index);
+               dout("__set_xattr_val p=%p\n", p);
+       }
+
+       dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n",
+            ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
+
+       return 0;
+}
+
+static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
+                          const char *name)
+{
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+       struct ceph_inode_xattr *xattr = NULL;
+       int c;
+
+       p = &ci->i_xattrs.index.rb_node;
+       while (*p) {
+               parent = *p;
+               xattr = rb_entry(parent, struct ceph_inode_xattr, node);
+               c = strncmp(name, xattr->name, xattr->name_len);
+               if (c < 0)
+                       p = &(*p)->rb_left;
+               else if (c > 0)
+                       p = &(*p)->rb_right;
+               else {
+                       dout("__get_xattr %s: found %.*s\n", name,
+                            xattr->val_len, xattr->val);
+                       return xattr;
+               }
+       }
+
+       dout("__get_xattr %s: not found\n", name);
+
+       return NULL;
+}
+
+static void __free_xattr(struct ceph_inode_xattr *xattr)
+{
+       BUG_ON(!xattr);
+
+       if (xattr->should_free_name)
+               kfree((void *)xattr->name);
+       if (xattr->should_free_val)
+               kfree((void *)xattr->val);
+
+       kfree(xattr);
+}
+
+static int __remove_xattr(struct ceph_inode_info *ci,
+                         struct ceph_inode_xattr *xattr)
+{
+       if (!xattr)
+               return -EOPNOTSUPP;
+
+       rb_erase(&xattr->node, &ci->i_xattrs.index);
+
+       if (xattr->should_free_name)
+               kfree((void *)xattr->name);
+       if (xattr->should_free_val)
+               kfree((void *)xattr->val);
+
+       ci->i_xattrs.names_size -= xattr->name_len;
+       ci->i_xattrs.vals_size -= xattr->val_len;
+       ci->i_xattrs.count--;
+       kfree(xattr);
+
+       return 0;
+}
+
+static int __remove_xattr_by_name(struct ceph_inode_info *ci,
+                          const char *name)
+{
+       struct rb_node **p;
+       struct ceph_inode_xattr *xattr;
+       int err;
+
+       p = &ci->i_xattrs.index.rb_node;
+       xattr = __get_xattr(ci, name);
+       err = __remove_xattr(ci, xattr);
+       return err;
+}
+
+static char *__copy_xattr_names(struct ceph_inode_info *ci,
+                               char *dest)
+{
+       struct rb_node *p;
+       struct ceph_inode_xattr *xattr = NULL;
+
+       p = rb_first(&ci->i_xattrs.index);
+       dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count);
+
+       while (p) {
+               xattr = rb_entry(p, struct ceph_inode_xattr, node);
+               memcpy(dest, xattr->name, xattr->name_len);
+               dest[xattr->name_len] = '\0';
+
+               dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name,
+                    xattr->name_len, ci->i_xattrs.names_size);
+
+               dest += xattr->name_len + 1;
+               p = rb_next(p);
+       }
+
+       return dest;
+}
+
+void __ceph_destroy_xattrs(struct ceph_inode_info *ci)
+{
+       struct rb_node *p, *tmp;
+       struct ceph_inode_xattr *xattr = NULL;
+
+       p = rb_first(&ci->i_xattrs.index);
+
+       dout("__ceph_destroy_xattrs p=%p\n", p);
+
+       while (p) {
+               xattr = rb_entry(p, struct ceph_inode_xattr, node);
+               tmp = p;
+               p = rb_next(tmp);
+               dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p,
+                    xattr->name_len, xattr->name);
+               rb_erase(tmp, &ci->i_xattrs.index);
+
+               __free_xattr(xattr);
+       }
+
+       ci->i_xattrs.names_size = 0;
+       ci->i_xattrs.vals_size = 0;
+       ci->i_xattrs.index_version = 0;
+       ci->i_xattrs.count = 0;
+       ci->i_xattrs.index = RB_ROOT;
+}
+
+static int __build_xattrs(struct inode *inode)
+{
+       u32 namelen;
+       u32 numattr = 0;
+       void *p, *end;
+       u32 len;
+       const char *name, *val;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int xattr_version;
+       struct ceph_inode_xattr **xattrs = NULL;
+       int err = 0;
+       int i;
+
+       dout("__build_xattrs() len=%d\n",
+            ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0);
+
+       if (ci->i_xattrs.index_version >= ci->i_xattrs.version)
+               return 0; /* already built */
+
+       __ceph_destroy_xattrs(ci);
+
+start:
+       /* updated internal xattr rb tree */
+       if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) {
+               p = ci->i_xattrs.blob->vec.iov_base;
+               end = p + ci->i_xattrs.blob->vec.iov_len;
+               ceph_decode_32_safe(&p, end, numattr, bad);
+               xattr_version = ci->i_xattrs.version;
+               spin_unlock(&inode->i_lock);
+
+               xattrs = kcalloc(numattr, sizeof(struct ceph_xattr *),
+                                GFP_NOFS);
+               err = -ENOMEM;
+               if (!xattrs)
+                       goto bad_lock;
+               memset(xattrs, 0, numattr*sizeof(struct ceph_xattr *));
+               for (i = 0; i < numattr; i++) {
+                       xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr),
+                                           GFP_NOFS);
+                       if (!xattrs[i])
+                               goto bad_lock;
+               }
+
+               spin_lock(&inode->i_lock);
+               if (ci->i_xattrs.version != xattr_version) {
+                       /* lost a race, retry */
+                       for (i = 0; i < numattr; i++)
+                               kfree(xattrs[i]);
+                       kfree(xattrs);
+                       goto start;
+               }
+               err = -EIO;
+               while (numattr--) {
+                       ceph_decode_32_safe(&p, end, len, bad);
+                       namelen = len;
+                       name = p;
+                       p += len;
+                       ceph_decode_32_safe(&p, end, len, bad);
+                       val = p;
+                       p += len;
+
+                       err = __set_xattr(ci, name, namelen, val, len,
+                                         0, 0, 0, &xattrs[numattr]);
+
+                       if (err < 0)
+                               goto bad;
+               }
+               kfree(xattrs);
+       }
+       ci->i_xattrs.index_version = ci->i_xattrs.version;
+       ci->i_xattrs.dirty = false;
+
+       return err;
+bad_lock:
+       spin_lock(&inode->i_lock);
+bad:
+       if (xattrs) {
+               for (i = 0; i < numattr; i++)
+                       kfree(xattrs[i]);
+               kfree(xattrs);
+       }
+       ci->i_xattrs.names_size = 0;
+       return err;
+}
+
+static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
+                                   int val_size)
+{
+       /*
+        * 4 bytes for the length, and additional 4 bytes per each xattr name,
+        * 4 bytes per each value
+        */
+       int size = 4 + ci->i_xattrs.count*(4 + 4) +
+                            ci->i_xattrs.names_size +
+                            ci->i_xattrs.vals_size;
+       dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n",
+            ci->i_xattrs.count, ci->i_xattrs.names_size,
+            ci->i_xattrs.vals_size);
+
+       if (name_size)
+               size += 4 + 4 + name_size + val_size;
+
+       return size;
+}
+
+/*
+ * If there are dirty xattrs, reencode xattrs into the prealloc_blob
+ * and swap into place.
+ */
+void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
+{
+       struct rb_node *p;
+       struct ceph_inode_xattr *xattr = NULL;
+       void *dest;
+
+       dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
+       if (ci->i_xattrs.dirty) {
+               int need = __get_required_blob_size(ci, 0, 0);
+
+               BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
+
+               p = rb_first(&ci->i_xattrs.index);
+               dest = ci->i_xattrs.prealloc_blob->vec.iov_base;
+
+               ceph_encode_32(&dest, ci->i_xattrs.count);
+               while (p) {
+                       xattr = rb_entry(p, struct ceph_inode_xattr, node);
+
+                       ceph_encode_32(&dest, xattr->name_len);
+                       memcpy(dest, xattr->name, xattr->name_len);
+                       dest += xattr->name_len;
+                       ceph_encode_32(&dest, xattr->val_len);
+                       memcpy(dest, xattr->val, xattr->val_len);
+                       dest += xattr->val_len;
+
+                       p = rb_next(p);
+               }
+
+               /* adjust buffer len; it may be larger than we need */
+               ci->i_xattrs.prealloc_blob->vec.iov_len =
+                       dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
+
+               if (ci->i_xattrs.blob)
+                       ceph_buffer_put(ci->i_xattrs.blob);
+               ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
+               ci->i_xattrs.prealloc_blob = NULL;
+               ci->i_xattrs.dirty = false;
+       }
+}
+
+ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
+                     size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       int err;
+       struct ceph_inode_xattr *xattr;
+       struct ceph_vxattr_cb *vxattr = NULL;
+
+       if (!ceph_is_valid_xattr(name))
+               return -ENODATA;
+
+       /* let's see if a virtual xattr was requested */
+       if (vxattrs)
+               vxattr = ceph_match_vxattr(vxattrs, name);
+
+       spin_lock(&inode->i_lock);
+       dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
+            ci->i_xattrs.version, ci->i_xattrs.index_version);
+
+       if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
+           (ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
+               goto get_xattr;
+       } else {
+               spin_unlock(&inode->i_lock);
+               /* get xattrs from mds (if we don't already have them) */
+               err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
+               if (err)
+                       return err;
+       }
+
+       spin_lock(&inode->i_lock);
+
+       if (vxattr && vxattr->readonly) {
+               err = vxattr->getxattr_cb(ci, value, size);
+               goto out;
+       }
+
+       err = __build_xattrs(inode);
+       if (err < 0)
+               goto out;
+
+get_xattr:
+       err = -ENODATA;  /* == ENOATTR */
+       xattr = __get_xattr(ci, name);
+       if (!xattr) {
+               if (vxattr)
+                       err = vxattr->getxattr_cb(ci, value, size);
+               goto out;
+       }
+
+       err = -ERANGE;
+       if (size && size < xattr->val_len)
+               goto out;
+
+       err = xattr->val_len;
+       if (size == 0)
+               goto out;
+
+       memcpy(value, xattr->val, xattr->val_len);
+
+out:
+       spin_unlock(&inode->i_lock);
+       return err;
+}
+
+ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       u32 vir_namelen = 0;
+       u32 namelen;
+       int err;
+       u32 len;
+       int i;
+
+       spin_lock(&inode->i_lock);
+       dout("listxattr %p ver=%lld index_ver=%lld\n", inode,
+            ci->i_xattrs.version, ci->i_xattrs.index_version);
+
+       if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
+           (ci->i_xattrs.index_version > ci->i_xattrs.version)) {
+               goto list_xattr;
+       } else {
+               spin_unlock(&inode->i_lock);
+               err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
+               if (err)
+                       return err;
+       }
+
+       spin_lock(&inode->i_lock);
+
+       err = __build_xattrs(inode);
+       if (err < 0)
+               goto out;
+
+list_xattr:
+       vir_namelen = 0;
+       /* include virtual dir xattrs */
+       if (vxattrs)
+               for (i = 0; vxattrs[i].name; i++)
+                       vir_namelen += strlen(vxattrs[i].name) + 1;
+       /* adding 1 byte per each variable due to the null termination */
+       namelen = vir_namelen + ci->i_xattrs.names_size + ci->i_xattrs.count;
+       err = -ERANGE;
+       if (size && namelen > size)
+               goto out;
+
+       err = namelen;
+       if (size == 0)
+               goto out;
+
+       names = __copy_xattr_names(ci, names);
+
+       /* virtual xattr names, too */
+       if (vxattrs)
+               for (i = 0; vxattrs[i].name; i++) {
+                       len = sprintf(names, "%s", vxattrs[i].name);
+                       names += len + 1;
+               }
+
+out:
+       spin_unlock(&inode->i_lock);
+       return err;
+}
+
+static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
+                             const char *value, size_t size, int flags)
+{
+       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct inode *parent_inode = dentry->d_parent->d_inode;
+       struct ceph_mds_request *req;
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       int err;
+       int i, nr_pages;
+       struct page **pages = NULL;
+       void *kaddr;
+
+       /* copy value into some pages */
+       nr_pages = calc_pages_for(0, size);
+       if (nr_pages) {
+               pages = kmalloc(sizeof(pages[0])*nr_pages, GFP_NOFS);
+               if (!pages)
+                       return -ENOMEM;
+               err = -ENOMEM;
+               for (i = 0; i < nr_pages; i++) {
+                       pages[i] = alloc_page(GFP_NOFS);
+                       if (!pages[i]) {
+                               nr_pages = i;
+                               goto out;
+                       }
+                       kaddr = kmap(pages[i]);
+                       memcpy(kaddr, value + i*PAGE_CACHE_SIZE,
+                              min(PAGE_CACHE_SIZE, size-i*PAGE_CACHE_SIZE));
+               }
+       }
+
+       dout("setxattr value=%.*s\n", (int)size, value);
+
+       /* do request */
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
+                                      USE_AUTH_MDS);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto out;
+       }
+       req->r_inode = igrab(inode);
+       req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
+       req->r_num_caps = 1;
+       req->r_args.setxattr.flags = cpu_to_le32(flags);
+       req->r_path2 = kstrdup(name, GFP_NOFS);
+
+       req->r_pages = pages;
+       req->r_num_pages = nr_pages;
+       req->r_data_len = size;
+
+       dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
+       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       ceph_mdsc_put_request(req);
+       dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
+
+out:
+       if (pages) {
+               for (i = 0; i < nr_pages; i++)
+                       __free_page(pages[i]);
+               kfree(pages);
+       }
+       return err;
+}
+
+int ceph_setxattr(struct dentry *dentry, const char *name,
+                 const void *value, size_t size, int flags)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       int err;
+       int name_len = strlen(name);
+       int val_len = size;
+       char *newname = NULL;
+       char *newval = NULL;
+       struct ceph_inode_xattr *xattr = NULL;
+       int issued;
+       int required_blob_size;
+
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       if (!ceph_is_valid_xattr(name))
+               return -EOPNOTSUPP;
+
+       if (vxattrs) {
+               struct ceph_vxattr_cb *vxattr =
+                       ceph_match_vxattr(vxattrs, name);
+               if (vxattr && vxattr->readonly)
+                       return -EOPNOTSUPP;
+       }
+
+       /* preallocate memory for xattr name, value, index node */
+       err = -ENOMEM;
+       newname = kmalloc(name_len + 1, GFP_NOFS);
+       if (!newname)
+               goto out;
+       memcpy(newname, name, name_len + 1);
+
+       if (val_len) {
+               newval = kmalloc(val_len + 1, GFP_NOFS);
+               if (!newval)
+                       goto out;
+               memcpy(newval, value, val_len);
+               newval[val_len] = '\0';
+       }
+
+       xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
+       if (!xattr)
+               goto out;
+
+       spin_lock(&inode->i_lock);
+retry:
+       issued = __ceph_caps_issued(ci, NULL);
+       if (!(issued & CEPH_CAP_XATTR_EXCL))
+               goto do_sync;
+       __build_xattrs(inode);
+
+       required_blob_size = __get_required_blob_size(ci, name_len, val_len);
+
+       if (!ci->i_xattrs.prealloc_blob ||
+           required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
+               struct ceph_buffer *blob = NULL;
+
+               spin_unlock(&inode->i_lock);
+               dout(" preaallocating new blob size=%d\n", required_blob_size);
+               blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
+               if (!blob)
+                       goto out;
+               spin_lock(&inode->i_lock);
+               if (ci->i_xattrs.prealloc_blob)
+                       ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+               ci->i_xattrs.prealloc_blob = blob;
+               goto retry;
+       }
+
+       dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
+       err = __set_xattr(ci, newname, name_len, newval,
+                         val_len, 1, 1, 1, &xattr);
+       __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+       ci->i_xattrs.dirty = true;
+       inode->i_ctime = CURRENT_TIME;
+       spin_unlock(&inode->i_lock);
+
+       return err;
+
+do_sync:
+       spin_unlock(&inode->i_lock);
+       err = ceph_sync_setxattr(dentry, name, value, size, flags);
+out:
+       kfree(newname);
+       kfree(newval);
+       kfree(xattr);
+       return err;
+}
+
+static int ceph_send_removexattr(struct dentry *dentry, const char *name)
+{
+       struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct inode *inode = dentry->d_inode;
+       struct inode *parent_inode = dentry->d_parent->d_inode;
+       struct ceph_mds_request *req;
+       int err;
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RMXATTR,
+                                      USE_AUTH_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       req->r_inode = igrab(inode);
+       req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
+       req->r_num_caps = 1;
+       req->r_path2 = kstrdup(name, GFP_NOFS);
+
+       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
+int ceph_removexattr(struct dentry *dentry, const char *name)
+{
+       struct inode *inode = dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       int issued;
+       int err;
+
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       if (!ceph_is_valid_xattr(name))
+               return -EOPNOTSUPP;
+
+       if (vxattrs) {
+               struct ceph_vxattr_cb *vxattr =
+                       ceph_match_vxattr(vxattrs, name);
+               if (vxattr && vxattr->readonly)
+                       return -EOPNOTSUPP;
+       }
+
+       spin_lock(&inode->i_lock);
+       __build_xattrs(inode);
+       issued = __ceph_caps_issued(ci, NULL);
+       dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
+
+       if (!(issued & CEPH_CAP_XATTR_EXCL))
+               goto do_sync;
+
+       err = __remove_xattr_by_name(ceph_inode(inode), name);
+       __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+       ci->i_xattrs.dirty = true;
+       inode->i_ctime = CURRENT_TIME;
+
+       spin_unlock(&inode->i_lock);
+
+       return err;
+do_sync:
+       spin_unlock(&inode->i_lock);
+       err = ceph_send_removexattr(dentry, name);
+       return err;
+}
+
index 8c6a036..5183bc2 100644 (file)
@@ -312,6 +312,7 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->clientCanCacheRead = false;
        cifs_inode->clientCanCacheAll = false;
        cifs_inode->delete_pending = false;
+       cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
        cifs_inode->server_eof = 0;
 
@@ -638,7 +639,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
                   setting the revalidate time to zero */
                CIFS_I(file->f_path.dentry->d_inode)->time = 0;
 
-               retval = cifs_revalidate(file->f_path.dentry);
+               retval = cifs_revalidate_file(file);
                if (retval < 0)
                        return (loff_t)retval;
        }
index 78c1b86..7aa57ec 100644 (file)
@@ -61,7 +61,8 @@ extern int cifs_mkdir(struct inode *, struct dentry *, int);
 extern int cifs_rmdir(struct inode *, struct dentry *);
 extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
                       struct dentry *);
-extern int cifs_revalidate(struct dentry *);
+extern int cifs_revalidate_file(struct file *filp);
+extern int cifs_revalidate_dentry(struct dentry *);
 extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int cifs_setattr(struct dentry *, struct iattr *);
 
index a1c817e..63c89d1 100644 (file)
@@ -389,6 +389,7 @@ struct cifsInodeInfo {
        bool clientCanCacheRead:1;      /* read oplock */
        bool clientCanCacheAll:1;       /* read and writebehind oplock */
        bool delete_pending:1;          /* DELETE_ON_CLOSE is set */
+       bool invalid_mapping:1;         /* pagecache is invalid */
        u64  server_eof;                /* current file size on server */
        u64  uniqueid;                  /* server inode number */
        struct inode vfs_inode;
index 88e2bc4..39e47f4 100644 (file)
@@ -104,10 +104,12 @@ 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_file_info(struct file *filp);
 extern int cifs_get_inode_info(struct inode **pinode,
                        const unsigned char *search_path,
                        FILE_ALL_INFO *pfile_info,
                        struct super_block *sb, int xid, const __u16 *pfid);
+extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, int xid);
@@ -142,6 +144,8 @@ extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
                        const __u16 search_handle);
 
+extern int CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+                       u16 netfid, FILE_ALL_INFO *pFindData);
 extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
                        FILE_ALL_INFO *findData,
@@ -152,6 +156,8 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
                        FILE_ALL_INFO *findData,
                        const struct nls_table *nls_codepage, int remap);
 
+extern int CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
+                       u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
 extern int CIFSSMBUnixQPathInfo(const int xid,
                        struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
index 6118358..7cc7f83 100644 (file)
@@ -500,7 +500,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        } else if (pSMBr->hdr.WordCount == 13) {
                cERROR(1, ("mount failed, cifs module not built "
                          "with CIFS_WEAK_PW_HASH support"));
-                       rc = -EOPNOTSUPP;
+               rc = -EOPNOTSUPP;
 #endif /* WEAK_PW_HASH */
                goto neg_err_exit;
        } else if (pSMBr->hdr.WordCount != 17) {
@@ -3230,8 +3230,72 @@ QInfRetry:
        return rc;
 }
 
+int
+CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+                u16 netfid, FILE_ALL_INFO *pFindData)
+{
+       struct smb_t2_qfi_req *pSMB = NULL;
+       struct smb_t2_qfi_rsp *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned;
+       __u16 params, byte_count;
 
+QFileInfoRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
 
+       params = 2 /* level */ + 2 /* fid */;
+       pSMB->t2.TotalDataCount = 0;
+       pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+       /* BB find exact max data count below from sess structure BB */
+       pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
+       pSMB->t2.MaxSetupCount = 0;
+       pSMB->t2.Reserved = 0;
+       pSMB->t2.Flags = 0;
+       pSMB->t2.Timeout = 0;
+       pSMB->t2.Reserved2 = 0;
+       pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+                                              Fid) - 4);
+       pSMB->t2.DataCount = 0;
+       pSMB->t2.DataOffset = 0;
+       pSMB->t2.SetupCount = 1;
+       pSMB->t2.Reserved3 = 0;
+       pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       byte_count = params + 1 /* pad */ ;
+       pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+       pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+       pSMB->Pad = 0;
+       pSMB->Fid = netfid;
+       pSMB->hdr.smb_buf_length += byte_count;
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Send error in QPathInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc) /* BB add auto retry on EOPNOTSUPP? */
+                       rc = -EIO;
+               else if (pSMBr->ByteCount < 40)
+                       rc = -EIO;      /* bad smb */
+               else if (pFindData) {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       memcpy((char *) pFindData,
+                              (char *) &pSMBr->hdr.Protocol +
+                              data_offset, sizeof(FILE_ALL_INFO));
+               } else
+                   rc = -ENOMEM;
+       }
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto QFileInfoRetry;
+
+       return rc;
+}
 
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
@@ -3335,6 +3399,75 @@ QPathInfoRetry:
 }
 
 int
+CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
+                u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
+{
+       struct smb_t2_qfi_req *pSMB = NULL;
+       struct smb_t2_qfi_rsp *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned;
+       __u16 params, byte_count;
+
+UnixQFileInfoRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 2 /* level */ + 2 /* fid */;
+       pSMB->t2.TotalDataCount = 0;
+       pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+       /* BB find exact max data count below from sess structure BB */
+       pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
+       pSMB->t2.MaxSetupCount = 0;
+       pSMB->t2.Reserved = 0;
+       pSMB->t2.Flags = 0;
+       pSMB->t2.Timeout = 0;
+       pSMB->t2.Reserved2 = 0;
+       pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+                                              Fid) - 4);
+       pSMB->t2.DataCount = 0;
+       pSMB->t2.DataOffset = 0;
+       pSMB->t2.SetupCount = 1;
+       pSMB->t2.Reserved3 = 0;
+       pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       byte_count = params + 1 /* pad */ ;
+       pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+       pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
+       pSMB->Pad = 0;
+       pSMB->Fid = netfid;
+       pSMB->hdr.smb_buf_length += byte_count;
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Send error in QPathInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
+                       cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
+                                  "Unix Extensions can be disabled on mount "
+                                  "by specifying the nosfu mount option."));
+                       rc = -EIO;      /* bad smb */
+               } else {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       memcpy((char *) pFindData,
+                              (char *) &pSMBr->hdr.Protocol +
+                              data_offset,
+                              sizeof(FILE_UNIX_BASIC_INFO));
+               }
+       }
+
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto UnixQFileInfoRetry;
+
+       return rc;
+}
+
+int
 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
                     const unsigned char *searchName,
                     FILE_UNIX_BASIC_INFO *pFindData,
index 6ccf726..e9f7ecc 100644 (file)
@@ -739,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
        int isValid = 1;
 
        if (direntry->d_inode) {
-               if (cifs_revalidate(direntry))
+               if (cifs_revalidate_dentry(direntry))
                        return 0;
        } else {
                cFYI(1, ("neg dentry 0x%p name = %s",
index 3d8f8a9..ca2ba7a 100644 (file)
@@ -219,8 +219,8 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                cFYI(1, ("inode unchanged on server"));
        } else {
                if (file->f_path.dentry->d_inode->i_mapping) {
-               /* BB no need to lock inode until after invalidate
-                  since namei code should already have it locked? */
+                       /* BB no need to lock inode until after invalidate
+                       since namei code should already have it locked? */
                        rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
                        if (rc != 0)
                                CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
@@ -1890,11 +1890,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 
 int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct dentry *dentry = file->f_path.dentry;
        int rc, xid;
 
        xid = GetXid();
-       rc = cifs_revalidate(dentry);
+       rc = cifs_revalidate_file(file);
        if (rc) {
                cFYI(1, ("Validation prior to mmap failed, error=%d", rc));
                FreeXid(xid);
index 8bdbc81..723daac 100644 (file)
@@ -77,6 +77,41 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
        }
 }
 
+/* check inode attributes against fattr. If they don't match, tag the
+ * inode for cache invalidation
+ */
+static void
+cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
+{
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+
+       cFYI(1, ("%s: revalidating inode %llu", __func__, cifs_i->uniqueid));
+
+       if (inode->i_state & I_NEW) {
+               cFYI(1, ("%s: inode %llu is new", __func__, cifs_i->uniqueid));
+               return;
+       }
+
+       /* don't bother with revalidation if we have an oplock */
+       if (cifs_i->clientCanCacheRead) {
+               cFYI(1, ("%s: inode %llu is oplocked", __func__,
+                        cifs_i->uniqueid));
+               return;
+       }
+
+        /* revalidate if mtime or size have changed */
+       if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
+           cifs_i->server_eof == fattr->cf_eof) {
+               cFYI(1, ("%s: inode %llu is unchanged", __func__,
+                        cifs_i->uniqueid));
+               return;
+       }
+
+       cFYI(1, ("%s: invalidating inode %llu mapping", __func__,
+                cifs_i->uniqueid));
+       cifs_i->invalid_mapping = true;
+}
+
 /* populate an inode with info from a cifs_fattr struct */
 void
 cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
@@ -85,6 +120,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        unsigned long oldtime = cifs_i->time;
 
+       cifs_revalidate_cache(inode, fattr);
+
        inode->i_atime = fattr->cf_atime;
        inode->i_mtime = fattr->cf_mtime;
        inode->i_ctime = fattr->cf_ctime;
@@ -231,6 +268,31 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
        fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
+int cifs_get_file_info_unix(struct file *filp)
+{
+       int rc;
+       int xid;
+       FILE_UNIX_BASIC_INFO find_data;
+       struct cifs_fattr fattr;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsTconInfo *tcon = cifs_sb->tcon;
+       struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+
+       xid = GetXid();
+       rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       if (!rc) {
+               cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, inode->i_sb);
+               rc = 0;
+       }
+
+       cifs_fattr_to_inode(inode, &fattr);
+       FreeXid(xid);
+       return rc;
+}
+
 int cifs_get_inode_info_unix(struct inode **pinode,
                             const unsigned char *full_path,
                             struct super_block *sb, int xid)
@@ -432,6 +494,47 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
+int cifs_get_file_info(struct file *filp)
+{
+       int rc;
+       int xid;
+       FILE_ALL_INFO find_data;
+       struct cifs_fattr fattr;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsTconInfo *tcon = cifs_sb->tcon;
+       struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+
+       xid = GetXid();
+       rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       if (rc == -EOPNOTSUPP || rc == -EINVAL) {
+               /*
+                * FIXME: legacy server -- fall back to path-based call?
+                * for now, just skip revalidating and mark inode for
+                * immediate reval.
+                */
+               rc = 0;
+               CIFS_I(inode)->time = 0;
+               goto cgfi_exit;
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, inode->i_sb);
+               rc = 0;
+       } else if (rc)
+               goto cgfi_exit;
+
+       /*
+        * don't bother with SFU junk here -- just mark inode as needing
+        * revalidation.
+        */
+       cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
+       fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
+       fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
+       cifs_fattr_to_inode(inode, &fattr);
+cgfi_exit:
+       FreeXid(xid);
+       return rc;
+}
+
 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)
@@ -1389,135 +1492,103 @@ cifs_rename_exit:
        return rc;
 }
 
-int cifs_revalidate(struct dentry *direntry)
+static bool
+cifs_inode_needs_reval(struct inode *inode)
 {
-       int xid;
-       int rc = 0, wbrc = 0;
-       char *full_path;
-       struct cifs_sb_info *cifs_sb;
-       struct cifsInodeInfo *cifsInode;
-       loff_t local_size;
-       struct timespec local_mtime;
-       bool invalidate_inode = false;
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
 
-       if (direntry->d_inode == NULL)
-               return -ENOENT;
+       if (cifs_i->clientCanCacheRead)
+               return false;
 
-       cifsInode = CIFS_I(direntry->d_inode);
+       if (!lookupCacheEnabled)
+               return true;
 
-       if (cifsInode == NULL)
-               return -ENOENT;
+       if (cifs_i->time == 0)
+               return true;
 
-       /* no sense revalidating inode info on file that no one can write */
-       if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
-               return rc;
+       /* FIXME: the actimeo should be tunable */
+       if (time_after_eq(jiffies, cifs_i->time + HZ))
+               return true;
+
+       return false;
+}
+
+/* check invalid_mapping flag and zap the cache if it's set */
+static void
+cifs_invalidate_mapping(struct inode *inode)
+{
+       int rc;
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+
+       cifs_i->invalid_mapping = false;
+
+       /* write back any cached data */
+       if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
+               rc = filemap_write_and_wait(inode->i_mapping);
+               if (rc)
+                       cifs_i->write_behind_rc = rc;
+       }
+       invalidate_remote_inode(inode);
+}
+
+int cifs_revalidate_file(struct file *filp)
+{
+       int rc = 0;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+
+       if (!cifs_inode_needs_reval(inode))
+               goto check_inval;
+
+       if (CIFS_SB(inode->i_sb)->tcon->unix_ext)
+               rc = cifs_get_file_info_unix(filp);
+       else
+               rc = cifs_get_file_info(filp);
+
+check_inval:
+       if (CIFS_I(inode)->invalid_mapping)
+               cifs_invalidate_mapping(inode);
+
+       return rc;
+}
+
+/* revalidate a dentry's inode attributes */
+int cifs_revalidate_dentry(struct dentry *dentry)
+{
+       int xid;
+       int rc = 0;
+       char *full_path = NULL;
+       struct inode *inode = dentry->d_inode;
+       struct super_block *sb = dentry->d_sb;
+
+       if (inode == NULL)
+               return -ENOENT;
 
        xid = GetXid();
 
-       cifs_sb = CIFS_SB(direntry->d_sb);
+       if (!cifs_inode_needs_reval(inode))
+               goto check_inval;
 
        /* can not safely grab the rename sem here if rename calls revalidate
           since that would deadlock */
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               FreeXid(xid);
-               return rc;
-       }
-       cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
-                "jiffies %ld", full_path, direntry->d_inode,
-                direntry->d_inode->i_count.counter, direntry,
-                direntry->d_time, jiffies));
-
-       if (cifsInode->time == 0) {
-               /* was set to zero previously to force revalidate */
-       } else if (time_before(jiffies, cifsInode->time + HZ) &&
-                  lookupCacheEnabled) {
-               if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
-                   (direntry->d_inode->i_nlink == 1)) {
-                       kfree(full_path);
-                       FreeXid(xid);
-                       return rc;
-               } else {
-                       cFYI(1, ("Have to revalidate file due to hardlinks"));
-               }
-       }
-
-       /* save mtime and size */
-       local_mtime = direntry->d_inode->i_mtime;
-       local_size = direntry->d_inode->i_size;
-
-       if (cifs_sb->tcon->unix_ext) {
-               rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
-                                             direntry->d_sb, xid);
-               if (rc) {
-                       cFYI(1, ("error on getting revalidate info %d", rc));
-/*                     if (rc != -ENOENT)
-                               rc = 0; */      /* BB should we cache info on
-                                                  certain errors? */
-               }
-       } else {
-               rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
-                                        direntry->d_sb, xid, NULL);
-               if (rc) {
-                       cFYI(1, ("error on getting revalidate info %d", rc));
-/*                     if (rc != -ENOENT)
-                               rc = 0; */      /* BB should we cache info on
-                                                  certain errors? */
-               }
+               goto check_inval;
        }
-       /* should we remap certain errors, access denied?, to zero */
 
-       /* if not oplocked, we invalidate inode pages if mtime or file size
-          had changed on server */
+       cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
+                "jiffies %ld", full_path, inode, inode->i_count.counter,
+                dentry, dentry->d_time, jiffies));
 
-       if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
-           (local_size == direntry->d_inode->i_size)) {
-               cFYI(1, ("cifs_revalidate - inode unchanged"));
-       } else {
-               /* file may have changed on server */
-               if (cifsInode->clientCanCacheRead) {
-                       /* no need to invalidate inode pages since we were the
-                          only ones who could have modified the file and the
-                          server copy is staler than ours */
-               } else {
-                       invalidate_inode = true;
-               }
-       }
+       if (CIFS_SB(sb)->tcon->unix_ext)
+               rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
+       else
+               rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
+                                        xid, NULL);
 
-       /* can not grab this sem since kernel filesys locking documentation
-          indicates i_mutex may be taken by the kernel on lookup and rename
-          which could deadlock if we grab the i_mutex here as well */
-/*     mutex_lock(&direntry->d_inode->i_mutex);*/
-       /* need to write out dirty pages here  */
-       if (direntry->d_inode->i_mapping) {
-               /* do we need to lock inode until after invalidate completes
-                  below? */
-               wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
-               if (wbrc)
-                       CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
-       }
-       if (invalidate_inode) {
-       /* shrink_dcache not necessary now that cifs dentry ops
-       are exported for negative dentries */
-/*             if (S_ISDIR(direntry->d_inode->i_mode))
-                       shrink_dcache_parent(direntry); */
-               if (S_ISREG(direntry->d_inode->i_mode)) {
-                       if (direntry->d_inode->i_mapping) {
-                               wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
-                               if (wbrc)
-                                       CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
-                       }
-                       /* may eventually have to do this for open files too */
-                       if (list_empty(&(cifsInode->openFileList))) {
-                               /* changed on server - flush read ahead pages */
-                               cFYI(1, ("Invalidating read ahead data on "
-                                        "closed file"));
-                               invalidate_remote_inode(direntry->d_inode);
-                       }
-               }
-       }
-/*     mutex_unlock(&direntry->d_inode->i_mutex); */
+check_inval:
+       if (CIFS_I(inode)->invalid_mapping)
+               cifs_invalidate_mapping(inode);
 
        kfree(full_path);
        FreeXid(xid);
@@ -1527,7 +1598,7 @@ int cifs_revalidate(struct dentry *direntry)
 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        struct kstat *stat)
 {
-       int err = cifs_revalidate(dentry);
+       int err = cifs_revalidate_dentry(dentry);
        if (!err) {
                generic_fillattr(dentry->d_inode, stat);
                stat->blksize = CIFS_MAX_MSGSIZE;
index e22de83..d32ee94 100644 (file)
@@ -567,7 +567,7 @@ static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
                        else BUG();
                }
        }
-       list->rb_node = NULL;
+       *list = RB_ROOT;
 }
 
 static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
index db30c0b..a2b8b4d 100644 (file)
@@ -782,6 +782,7 @@ struct svc_version nfs4_callback_version1 = {
        .vs_proc = nfs4_callback_procedures1,
        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
        .vs_dispatch = NULL,
+       .vs_hidden = 1,
 };
 
 struct svc_version nfs4_callback_version4 = {
index 944b627..69e7b81 100644 (file)
@@ -71,4 +71,10 @@ static inline int nfs_inode_return_delegation(struct inode *inode)
 }
 #endif
 
+static inline int nfs_have_delegated_attributes(struct inode *inode)
+{
+       return nfs_have_delegation(inode, FMODE_READ) &&
+               !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED);
+}
+
 #endif
index a1f6b44..c6f2750 100644 (file)
@@ -1789,7 +1789,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
        cache = nfs_access_search_rbtree(inode, cred);
        if (cache == NULL)
                goto out;
-       if (!nfs_have_delegation(inode, FMODE_READ) &&
+       if (!nfs_have_delegated_attributes(inode) &&
            !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
                goto out_stale;
        res->jiffies = cache->jiffies;
index 657201a..e358df7 100644 (file)
@@ -729,7 +729,7 @@ int nfs_attribute_timeout(struct inode *inode)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       if (nfs_have_delegation(inode, FMODE_READ))
+       if (nfs_have_delegated_attributes(inode))
                return 0;
        return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
 }
index eda74c4..f9254fb 100644 (file)
@@ -5107,6 +5107,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
        res = kzalloc(sizeof(*res), GFP_KERNEL);
        if (!args || !res) {
                kfree(args);
+               kfree(res);
                nfs_put_client(clp);
                return -ENOMEM;
        }
index a12c45b..29d9d36 100644 (file)
@@ -112,12 +112,10 @@ void nfs_unlock_request(struct nfs_page *req)
  */
 int nfs_set_page_tag_locked(struct nfs_page *req)
 {
-       struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
-
        if (!nfs_lock_request_dontget(req))
                return 0;
        if (req->wb_page != NULL)
-               radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
+               radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
        return 1;
 }
 
@@ -126,10 +124,10 @@ int nfs_set_page_tag_locked(struct nfs_page *req)
  */
 void nfs_clear_page_tag_locked(struct nfs_page *req)
 {
-       struct inode *inode = req->wb_context->path.dentry->d_inode;
-       struct nfs_inode *nfsi = NFS_I(inode);
-
        if (req->wb_page != NULL) {
+               struct inode *inode = req->wb_context->path.dentry->d_inode;
+               struct nfs_inode *nfsi = NFS_I(inode);
+
                spin_lock(&inode->i_lock);
                radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
                nfs_unlock_request(req);
@@ -142,16 +140,22 @@ void nfs_clear_page_tag_locked(struct nfs_page *req)
  * nfs_clear_request - Free up all resources allocated to the request
  * @req:
  *
- * Release page resources associated with a write request after it
- * has completed.
+ * Release page and open context resources associated with a read/write
+ * request after it has completed.
  */
 void nfs_clear_request(struct nfs_page *req)
 {
        struct page *page = req->wb_page;
+       struct nfs_open_context *ctx = req->wb_context;
+
        if (page != NULL) {
                page_cache_release(page);
                req->wb_page = NULL;
        }
+       if (ctx != NULL) {
+               put_nfs_open_context(ctx);
+               req->wb_context = NULL;
+       }
 }
 
 
@@ -165,9 +169,8 @@ static void nfs_free_request(struct kref *kref)
 {
        struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);
 
-       /* Release struct file or cached credential */
+       /* Release struct file and open context */
        nfs_clear_request(req);
-       put_nfs_open_context(req->wb_context);
        nfs_page_free(req);
 }
 
index f1afee4..6baf9a3 100644 (file)
@@ -2214,7 +2214,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        } else {
                error = nfs_bdi_register(server);
                if (error)
-                       goto error_splat_super;
+                       goto error_splat_bdi;
        }
 
        if (!s->s_root) {
@@ -2256,6 +2256,9 @@ out_err_nosb:
 error_splat_root:
        dput(mntroot);
 error_splat_super:
+       if (server && !s->s_root)
+               bdi_unregister(&server->backing_dev_info);
+error_splat_bdi:
        deactivate_locked_super(s);
        goto out;
 }
@@ -2326,7 +2329,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
        } else {
                error = nfs_bdi_register(server);
                if (error)
-                       goto error_splat_super;
+                       goto error_splat_bdi;
        }
 
        if (!s->s_root) {
@@ -2363,6 +2366,9 @@ out_err_noserver:
        return error;
 
 error_splat_super:
+       if (server && !s->s_root)
+               bdi_unregister(&server->backing_dev_info);
+error_splat_bdi:
        deactivate_locked_super(s);
        dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
        return error;
@@ -2578,7 +2584,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type,
        } else {
                error = nfs_bdi_register(server);
                if (error)
-                       goto error_splat_super;
+                       goto error_splat_bdi;
        }
 
        if (!s->s_root) {
@@ -2616,6 +2622,9 @@ out_free:
 error_splat_root:
        dput(mntroot);
 error_splat_super:
+       if (server && !s->s_root)
+               bdi_unregister(&server->backing_dev_info);
+error_splat_bdi:
        deactivate_locked_super(s);
        goto out;
 }
@@ -2811,7 +2820,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
        } else {
                error = nfs_bdi_register(server);
                if (error)
-                       goto error_splat_super;
+                       goto error_splat_bdi;
        }
 
        if (!s->s_root) {
@@ -2847,6 +2856,9 @@ out_err_noserver:
        return error;
 
 error_splat_super:
+       if (server && !s->s_root)
+               bdi_unregister(&server->backing_dev_info);
+error_splat_bdi:
        deactivate_locked_super(s);
        dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
        return error;
@@ -2893,7 +2905,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
        } else {
                error = nfs_bdi_register(server);
                if (error)
-                       goto error_splat_super;
+                       goto error_splat_bdi;
        }
 
        if (!s->s_root) {
@@ -2929,6 +2941,9 @@ out_err_noserver:
        return error;
 
 error_splat_super:
+       if (server && !s->s_root)
+               bdi_unregister(&server->backing_dev_info);
+error_splat_bdi:
        deactivate_locked_super(s);
        dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
        return error;
index 1cf39df..0de1db6 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/vfs.h>
 #include <linux/moduleparam.h>
 #include <linux/smp_lock.h>
+#include <linux/bitmap.h>
 
 #include "sysctl.h"
 #include "logfile.h"
@@ -2458,7 +2459,6 @@ static void ntfs_put_super(struct super_block *sb)
 static s64 get_nr_free_clusters(ntfs_volume *vol)
 {
        s64 nr_free = vol->nr_clusters;
-       u32 *kaddr;
        struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
        struct page *page;
        pgoff_t index, max_index;
@@ -2477,7 +2477,8 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
        ntfs_debug("Reading $Bitmap, max_index = 0x%lx, max_size = 0x%lx.",
                        max_index, PAGE_CACHE_SIZE / 4);
        for (index = 0; index < max_index; index++) {
-               unsigned int i;
+               unsigned long *kaddr;
+
                /*
                 * Read the page from page cache, getting it from backing store
                 * if necessary, and increment the use count.
@@ -2490,16 +2491,16 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
                        nr_free -= PAGE_CACHE_SIZE * 8;
                        continue;
                }
-               kaddr = (u32*)kmap_atomic(page, KM_USER0);
+               kaddr = kmap_atomic(page, KM_USER0);
                /*
-                * For each 4 bytes, subtract the number of set bits. If this
+                * Subtract the number of set bits. If this
                 * is the last page and it is partial we don't really care as
                 * it just means we do a little extra work but it won't affect
                 * the result as all out of range bytes are set to zero by
                 * ntfs_readpage().
                 */
-               for (i = 0; i < PAGE_CACHE_SIZE / 4; i++)
-                       nr_free -= (s64)hweight32(kaddr[i]);
+               nr_free -= bitmap_weight(kaddr,
+                                       PAGE_CACHE_SIZE * BITS_PER_BYTE);
                kunmap_atomic(kaddr, KM_USER0);
                page_cache_release(page);
        }
@@ -2538,7 +2539,6 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
 static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
                s64 nr_free, const pgoff_t max_index)
 {
-       u32 *kaddr;
        struct address_space *mapping = vol->mftbmp_ino->i_mapping;
        struct page *page;
        pgoff_t index;
@@ -2548,7 +2548,8 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
        ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
                        "0x%lx.", max_index, PAGE_CACHE_SIZE / 4);
        for (index = 0; index < max_index; index++) {
-               unsigned int i;
+               unsigned long *kaddr;
+
                /*
                 * Read the page from page cache, getting it from backing store
                 * if necessary, and increment the use count.
@@ -2561,16 +2562,16 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
                        nr_free -= PAGE_CACHE_SIZE * 8;
                        continue;
                }
-               kaddr = (u32*)kmap_atomic(page, KM_USER0);
+               kaddr = kmap_atomic(page, KM_USER0);
                /*
-                * For each 4 bytes, subtract the number of set bits. If this
+                * Subtract the number of set bits. If this
                 * is the last page and it is partial we don't really care as
                 * it just means we do a little extra work but it won't affect
                 * the result as all out of range bytes are set to zero by
                 * ntfs_readpage().
                 */
-               for (i = 0; i < PAGE_CACHE_SIZE / 4; i++)
-                       nr_free -= (s64)hweight32(kaddr[i]);
+               nr_free -= bitmap_weight(kaddr,
+                                       PAGE_CACHE_SIZE * BITS_PER_BYTE);
                kunmap_atomic(kaddr, KM_USER0);
                page_cache_release(page);
        }
index 9083357..9962850 100644 (file)
@@ -932,6 +932,9 @@ xfs_aops_discard_page(
        if (!xfs_is_delayed_page(page, IOMAP_DELAY))
                goto out_invalidate;
 
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               goto out_invalidate;
+
        xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
                "page discard on page %p, inode 0x%llx, offset %llu.",
                        page, ip->i_ino, offset);
@@ -964,8 +967,10 @@ xfs_aops_discard_page(
 
                if (error) {
                        /* something screwed, just bail */
-                       xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
-                       "page discard failed delalloc mapping lookup.");
+                       if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+                               xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+                               "page discard failed delalloc mapping lookup.");
+                       }
                        break;
                }
                if (!nimaps) {
@@ -991,8 +996,10 @@ xfs_aops_discard_page(
                ASSERT(!flist.xbf_count && !flist.xbf_first);
                if (error) {
                        /* something screwed, just bail */
-                       xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+                       if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+                               xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
                        "page discard unable to remove delalloc mapping.");
+                       }
                        break;
                }
 next_buffer:
index 6f76ba8..bd111b7 100644 (file)
@@ -168,75 +168,6 @@ test_page_region(
 }
 
 /*
- *     Mapping of multi-page buffers into contiguous virtual space
- */
-
-typedef struct a_list {
-       void            *vm_addr;
-       struct a_list   *next;
-} a_list_t;
-
-static a_list_t                *as_free_head;
-static int             as_list_len;
-static DEFINE_SPINLOCK(as_lock);
-
-/*
- *     Try to batch vunmaps because they are costly.
- */
-STATIC void
-free_address(
-       void            *addr)
-{
-       a_list_t        *aentry;
-
-#ifdef CONFIG_XEN
-       /*
-        * Xen needs to be able to make sure it can get an exclusive
-        * RO mapping of pages it wants to turn into a pagetable.  If
-        * a newly allocated page is also still being vmap()ed by xfs,
-        * it will cause pagetable construction to fail.  This is a
-        * quick workaround to always eagerly unmap pages so that Xen
-        * is happy.
-        */
-       vunmap(addr);
-       return;
-#endif
-
-       aentry = kmalloc(sizeof(a_list_t), GFP_NOWAIT);
-       if (likely(aentry)) {
-               spin_lock(&as_lock);
-               aentry->next = as_free_head;
-               aentry->vm_addr = addr;
-               as_free_head = aentry;
-               as_list_len++;
-               spin_unlock(&as_lock);
-       } else {
-               vunmap(addr);
-       }
-}
-
-STATIC void
-purge_addresses(void)
-{
-       a_list_t        *aentry, *old;
-
-       if (as_free_head == NULL)
-               return;
-
-       spin_lock(&as_lock);
-       aentry = as_free_head;
-       as_free_head = NULL;
-       as_list_len = 0;
-       spin_unlock(&as_lock);
-
-       while ((old = aentry) != NULL) {
-               vunmap(aentry->vm_addr);
-               aentry = aentry->next;
-               kfree(old);
-       }
-}
-
-/*
  *     Internal xfs_buf_t object manipulation
  */
 
@@ -337,7 +268,8 @@ xfs_buf_free(
                uint            i;
 
                if (xfs_buf_is_vmapped(bp))
-                       free_address(bp->b_addr - bp->b_offset);
+                       vm_unmap_ram(bp->b_addr - bp->b_offset,
+                                       bp->b_page_count);
 
                for (i = 0; i < bp->b_page_count; i++) {
                        struct page     *page = bp->b_pages[i];
@@ -457,10 +389,8 @@ _xfs_buf_map_pages(
                bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset;
                bp->b_flags |= XBF_MAPPED;
        } else if (flags & XBF_MAPPED) {
-               if (as_list_len > 64)
-                       purge_addresses();
-               bp->b_addr = vmap(bp->b_pages, bp->b_page_count,
-                                       VM_MAP, PAGE_KERNEL);
+               bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count,
+                                       -1, PAGE_KERNEL);
                if (unlikely(bp->b_addr == NULL))
                        return -ENOMEM;
                bp->b_addr += bp->b_offset;
@@ -1955,9 +1885,6 @@ xfsbufd(
                        xfs_buf_iostrategy(bp);
                        count++;
                }
-
-               if (as_list_len > 0)
-                       purge_addresses();
                if (count)
                        blk_run_address_space(target->bt_mapping);
 
index 29c0448..ca16c38 100644 (file)
 #define CLCD_UBAS              0x00000010
 #define CLCD_LBAS              0x00000014
 
-#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW)
-#define CLCD_IENB              0x00000018
-#define CLCD_CNTL              0x0000001c
-#else
-/*
- * Someone rearranged these two registers on the Versatile
- * platform...
- */
-#define CLCD_IENB              0x0000001c
-#define CLCD_CNTL              0x00000018
-#endif
-
-#define CLCD_STAT              0x00000020
-#define CLCD_INTR              0x00000024
-#define CLCD_UCUR              0x00000028
-#define CLCD_LCUR              0x0000002C
+#define CLCD_PL110_IENB                0x00000018
+#define CLCD_PL110_CNTL                0x0000001c
+#define CLCD_PL110_STAT                0x00000020
+#define CLCD_PL110_INTR        0x00000024
+#define CLCD_PL110_UCUR                0x00000028
+#define CLCD_PL110_LCUR                0x0000002C
+
+#define CLCD_PL111_CNTL                0x00000018
+#define CLCD_PL111_IENB                0x0000001c
+#define CLCD_PL111_RIS         0x00000020
+#define CLCD_PL111_MIS         0x00000024
+#define CLCD_PL111_ICR         0x00000028
+#define CLCD_PL111_UCUR                0x0000002c
+#define CLCD_PL111_LCUR                0x00000030
+
 #define CLCD_PALL              0x00000200
 #define CLCD_PALETTE           0x00000200
 
@@ -147,6 +146,8 @@ struct clcd_fb {
        struct clcd_board       *board;
        void                    *board_data;
        void __iomem            *regs;
+       u16                     off_ienb;
+       u16                     off_cntl;
        u32                     clcd_cntl;
        u32                     cmap[16];
 };
index 8c4f884..4a3d52e 100644 (file)
@@ -36,18 +36,18 @@ struct backlight_device;
 struct fb_info;
 
 struct backlight_ops {
-       const unsigned int options;
+       unsigned int options;
 
 #define BL_CORE_SUSPENDRESUME  (1 << 0)
 
        /* Notify the backlight driver some property has changed */
-       int (* const update_status)(struct backlight_device *);
+       int (*update_status)(struct backlight_device *);
        /* Return the current backlight brightness (accounting for power,
           fb_blank etc.) */
-       int (* const get_brightness)(struct backlight_device *);
+       int (*get_brightness)(struct backlight_device *);
        /* Check if given framebuffer device is the one bound to this backlight;
           return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */
-       int (* const check_fb)(struct fb_info *);
+       int (*check_fb)(struct backlight_device *, struct fb_info *);
 };
 
 /* This structure defines all the properties of a backlight */
@@ -103,7 +103,8 @@ static inline void backlight_update_status(struct backlight_device *bd)
 }
 
 extern struct backlight_device *backlight_device_register(const char *name,
-       struct device *dev, void *devdata, const struct backlight_ops *ops);
+       struct device *dev, void *devdata, const struct backlight_ops *ops,
+       const struct backlight_properties *props);
 extern void backlight_device_unregister(struct backlight_device *bd);
 extern void backlight_force_update(struct backlight_device *bd,
                                   enum backlight_update_reason reason);
index 6b7c444..c0f4b36 100644 (file)
@@ -131,12 +131,12 @@ struct ftrace_event_call {
        void                    *mod;
        void                    *data;
 
-       int                     profile_count;
-       int                     (*profile_enable)(struct ftrace_event_call *);
-       void                    (*profile_disable)(struct ftrace_event_call *);
+       int                     perf_refcount;
+       int                     (*perf_event_enable)(struct ftrace_event_call *);
+       void                    (*perf_event_disable)(struct ftrace_event_call *);
 };
 
-#define FTRACE_MAX_PROFILE_SIZE        2048
+#define PERF_MAX_TRACE_SIZE    2048
 
 #define MAX_FILTER_PRED                32
 #define MAX_FILTER_STR_VAL     256     /* Should handle KSYM_SYMBOL_LEN */
@@ -187,22 +187,25 @@ do {                                                                      \
 
 #ifdef CONFIG_PERF_EVENTS
 struct perf_event;
-extern int ftrace_profile_enable(int event_id);
-extern void ftrace_profile_disable(int event_id);
+
+DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
+
+extern int perf_trace_enable(int event_id);
+extern void perf_trace_disable(int event_id);
 extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
                                     char *filter_str);
 extern void ftrace_profile_free_filter(struct perf_event *event);
 extern void *
-ftrace_perf_buf_prepare(int size, unsigned short type, int *rctxp,
+perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,
                         unsigned long *irq_flags);
 
 static inline void
-ftrace_perf_buf_submit(void *raw_data, int size, int rctx, u64 addr,
-                      u64 count, unsigned long irq_flags)
+perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
+                      u64 count, unsigned long irq_flags, struct pt_regs *regs)
 {
        struct trace_entry *entry = raw_data;
 
-       perf_tp_event(entry->type, addr, count, raw_data, size);
+       perf_tp_event(entry->type, addr, count, raw_data, size, regs);
        perf_swevent_put_recursion_context(rctx);
        local_irq_restore(irq_flags);
 }
index 1adfe77..85582e1 100644 (file)
@@ -36,6 +36,8 @@ struct memory_block {
        struct sys_device sysdev;
 };
 
+int arch_get_memory_phys_device(unsigned long start_pfn);
+
 /* These states are exposed to userspace as text strings in sysfs */
 #define        MEM_ONLINE              (1<<0) /* exposed to userspace */
 #define        MEM_GOING_OFFLINE       (1<<1) /* exposed to userspace */
index f6d9cbc..a367e19 100644 (file)
@@ -127,7 +127,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
 
 /* Default string compare functions, Allow arch asm/prom.h to override */
 #if !defined(of_compat_cmp)
-#define of_compat_cmp(s1, s2, l)       strncasecmp((s1), (s2), (l))
+#define of_compat_cmp(s1, s2, l)       strcasecmp((s1), (s2))
 #define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
 #define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
 #endif
index 6f8cd7d..9547703 100644 (file)
@@ -452,6 +452,8 @@ enum perf_callchain_context {
 #include <linux/fs.h>
 #include <linux/pid_namespace.h>
 #include <linux/workqueue.h>
+#include <linux/ftrace.h>
+#include <linux/cpu.h>
 #include <asm/atomic.h>
 
 #define PERF_MAX_STACK_DEPTH           255
@@ -847,6 +849,44 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
                __perf_sw_event(event_id, nr, nmi, regs, addr);
 }
 
+extern void
+perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
+
+/*
+ * Take a snapshot of the regs. Skip ip and frame pointer to
+ * the nth caller. We only need a few of the regs:
+ * - ip for PERF_SAMPLE_IP
+ * - cs for user_mode() tests
+ * - bp for callchains
+ * - eflags, for future purposes, just in case
+ */
+static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip)
+{
+       unsigned long ip;
+
+       memset(regs, 0, sizeof(*regs));
+
+       switch (skip) {
+       case 1 :
+               ip = CALLER_ADDR0;
+               break;
+       case 2 :
+               ip = CALLER_ADDR1;
+               break;
+       case 3 :
+               ip = CALLER_ADDR2;
+               break;
+       case 4:
+               ip = CALLER_ADDR3;
+               break;
+       /* No need to support further for now */
+       default:
+               ip = 0;
+       }
+
+       return perf_arch_fetch_caller_regs(regs, ip, skip);
+}
+
 extern void __perf_event_mmap(struct vm_area_struct *vma);
 
 static inline void perf_event_mmap(struct vm_area_struct *vma)
@@ -880,7 +920,8 @@ static inline bool perf_paranoid_kernel(void)
 }
 
 extern void perf_event_init(void);
-extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, int entry_size);
+extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
+                         int entry_size, struct pt_regs *regs);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
@@ -936,5 +977,21 @@ static inline void perf_event_disable(struct perf_event *event)            { }
 #define perf_output_put(handle, x) \
        perf_output_copy((handle), &(x), sizeof(x))
 
+/*
+ * This has to have a higher priority than migration_notifier in sched.c.
+ */
+#define perf_cpu_notifier(fn)                                  \
+do {                                                           \
+       static struct notifier_block fn##_nb __cpuinitdata =    \
+               { .notifier_call = fn, .priority = 20 };        \
+       fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE,             \
+               (void *)(unsigned long)smp_processor_id());     \
+       fn(&fn##_nb, (unsigned long)CPU_STARTING,               \
+               (void *)(unsigned long)smp_processor_id());     \
+       fn(&fn##_nb, (unsigned long)CPU_ONLINE,                 \
+               (void *)(unsigned long)smp_processor_id());     \
+       register_cpu_notifier(&fn##_nb);                        \
+} while (0)
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/include/linux/spi/l4f00242t03.h b/include/linux/spi/l4f00242t03.h
new file mode 100644 (file)
index 0000000..aee1dbd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * l4f00242t03.h -- Platform glue for Epson L4F00242T03 LCD
+ *
+ * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ * Based on Marek Vasut work in lms283gf05.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _INCLUDE_LINUX_SPI_L4F00242T03_H_
+#define _INCLUDE_LINUX_SPI_L4F00242T03_H_
+
+struct l4f00242t03_pdata {
+       unsigned int    reset_gpio;
+       unsigned int    data_enable_gpio;
+       const char      *io_supply;     /* will be set to 1.8 V */
+       const char      *core_supply;   /* will be set to 2.8 V */
+};
+
+#endif /* _INCLUDE_LINUX_SPI_L4F00242T03_H_ */
index 44f2ad0..f994ae5 100644 (file)
@@ -105,18 +105,18 @@ struct perf_event_attr;
 
 #ifdef CONFIG_PERF_EVENTS
 
-#define TRACE_SYS_ENTER_PROFILE_INIT(sname)                                   \
-       .profile_enable = prof_sysenter_enable,                                \
-       .profile_disable = prof_sysenter_disable,
+#define TRACE_SYS_ENTER_PERF_INIT(sname)                                      \
+       .perf_event_enable = perf_sysenter_enable,                             \
+       .perf_event_disable = perf_sysenter_disable,
 
-#define TRACE_SYS_EXIT_PROFILE_INIT(sname)                                    \
-       .profile_enable = prof_sysexit_enable,                                 \
-       .profile_disable = prof_sysexit_disable,
+#define TRACE_SYS_EXIT_PERF_INIT(sname)                                               \
+       .perf_event_enable = perf_sysexit_enable,                              \
+       .perf_event_disable = perf_sysexit_disable,
 #else
-#define TRACE_SYS_ENTER_PROFILE(sname)
-#define TRACE_SYS_ENTER_PROFILE_INIT(sname)
-#define TRACE_SYS_EXIT_PROFILE(sname)
-#define TRACE_SYS_EXIT_PROFILE_INIT(sname)
+#define TRACE_SYS_ENTER_PERF(sname)
+#define TRACE_SYS_ENTER_PERF_INIT(sname)
+#define TRACE_SYS_EXIT_PERF(sname)
+#define TRACE_SYS_EXIT_PERF_INIT(sname)
 #endif /* CONFIG_PERF_EVENTS */
 
 #ifdef CONFIG_FTRACE_SYSCALLS
@@ -153,7 +153,7 @@ struct perf_event_attr;
                .regfunc                = reg_event_syscall_enter,      \
                .unregfunc              = unreg_event_syscall_enter,    \
                .data                   = (void *)&__syscall_meta_##sname,\
-               TRACE_SYS_ENTER_PROFILE_INIT(sname)                     \
+               TRACE_SYS_ENTER_PERF_INIT(sname)                        \
        }
 
 #define SYSCALL_TRACE_EXIT_EVENT(sname)                                        \
@@ -175,7 +175,7 @@ struct perf_event_attr;
                .regfunc                = reg_event_syscall_exit,       \
                .unregfunc              = unreg_event_syscall_exit,     \
                .data                   = (void *)&__syscall_meta_##sname,\
-               TRACE_SYS_EXIT_PROFILE_INIT(sname)                      \
+               TRACE_SYS_EXIT_PERF_INIT(sname)                 \
        }
 
 #define SYSCALL_METADATA(sname, nb)                            \
index ff92b46..ae5196a 100644 (file)
@@ -338,7 +338,8 @@ struct iscsi_host {
 extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
                                    int reason);
 extern int iscsi_eh_abort(struct scsi_cmnd *sc);
-extern int iscsi_eh_target_reset(struct scsi_cmnd *sc);
+extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
+extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
 extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
 extern int iscsi_queuecommand(struct scsi_cmnd *sc,
                              void (*done)(struct scsi_cmnd *));
index 601ad77..ea6f9d4 100644 (file)
@@ -401,18 +401,18 @@ static inline notrace int ftrace_get_offsets_##call(                      \
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)                      \
                                                                        \
-static void ftrace_profile_##name(proto);                              \
+static void perf_trace_##name(proto);                                  \
                                                                        \
 static notrace int                                                     \
-ftrace_profile_enable_##name(struct ftrace_event_call *unused)         \
+perf_trace_enable_##name(struct ftrace_event_call *unused)             \
 {                                                                      \
-       return register_trace_##name(ftrace_profile_##name);            \
+       return register_trace_##name(perf_trace_##name);                \
 }                                                                      \
                                                                        \
 static notrace void                                                    \
-ftrace_profile_disable_##name(struct ftrace_event_call *unused)                \
+perf_trace_disable_##name(struct ftrace_event_call *unused)            \
 {                                                                      \
-       unregister_trace_##name(ftrace_profile_##name);                 \
+       unregister_trace_##name(perf_trace_##name);                     \
 }
 
 #undef DEFINE_EVENT_PRINT
@@ -507,12 +507,12 @@ ftrace_profile_disable_##name(struct ftrace_event_call *unused)           \
 
 #ifdef CONFIG_PERF_EVENTS
 
-#define _TRACE_PROFILE_INIT(call)                                      \
-       .profile_enable = ftrace_profile_enable_##call,                 \
-       .profile_disable = ftrace_profile_disable_##call,
+#define _TRACE_PERF_INIT(call)                                         \
+       .perf_event_enable = perf_trace_enable_##call,                  \
+       .perf_event_disable = perf_trace_disable_##call,
 
 #else
-#define _TRACE_PROFILE_INIT(call)
+#define _TRACE_PERF_INIT(call)
 #endif /* CONFIG_PERF_EVENTS */
 
 #undef __entry
@@ -638,7 +638,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
        .unregfunc              = ftrace_raw_unreg_event_##call,        \
        .print_fmt              = print_fmt_##template,                 \
        .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PROFILE_INIT(call)                                       \
+       _TRACE_PERF_INIT(call)                                  \
 }
 
 #undef DEFINE_EVENT_PRINT
@@ -657,18 +657,18 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
        .unregfunc              = ftrace_raw_unreg_event_##call,        \
        .print_fmt              = print_fmt_##call,                     \
        .define_fields          = ftrace_define_fields_##template,      \
-       _TRACE_PROFILE_INIT(call)                                       \
+       _TRACE_PERF_INIT(call)                                  \
 }
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
- * Define the insertion callback to profile events
+ * Define the insertion callback to perf events
  *
  * The job is very similar to ftrace_raw_event_<call> except that we don't
  * insert in the ring buffer but in a perf counter.
  *
- * static void ftrace_profile_<call>(proto)
+ * static void ftrace_perf_<call>(proto)
  * {
  *     struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
  *     struct ftrace_event_call *event_call = &event_<call>;
@@ -757,13 +757,14 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static notrace void                                                    \
-ftrace_profile_templ_##call(struct ftrace_event_call *event_call,      \
+perf_trace_templ_##call(struct ftrace_event_call *event_call,          \
                            proto)                                      \
 {                                                                      \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ftrace_raw_##call *entry;                                \
        u64 __addr = 0, __count = 1;                                    \
        unsigned long irq_flags;                                        \
+       struct pt_regs *__regs;                                         \
        int __entry_size;                                               \
        int __data_size;                                                \
        int rctx;                                                       \
@@ -773,10 +774,10 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \
                             sizeof(u64));                              \
        __entry_size -= sizeof(u32);                                    \
                                                                        \
-       if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE,           \
+       if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE,               \
                      "profile buffer not large enough"))               \
                return;                                                 \
-       entry = (struct ftrace_raw_##call *)ftrace_perf_buf_prepare(    \
+       entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
                __entry_size, event_call->id, &rctx, &irq_flags);       \
        if (!entry)                                                     \
                return;                                                 \
@@ -784,17 +785,20 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \
                                                                        \
        { assign; }                                                     \
                                                                        \
-       ftrace_perf_buf_submit(entry, __entry_size, rctx, __addr,       \
-                              __count, irq_flags);                     \
+       __regs = &__get_cpu_var(perf_trace_regs);                       \
+       perf_fetch_caller_regs(__regs, 2);                              \
+                                                                       \
+       perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
+                              __count, irq_flags, __regs);             \
 }
 
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)              \
-static notrace void ftrace_profile_##call(proto)               \
+static notrace void perf_trace_##call(proto)                   \
 {                                                              \
        struct ftrace_event_call *event_call = &event_##call;   \
                                                                \
-       ftrace_profile_templ_##template(event_call, args);      \
+       perf_trace_templ_##template(event_call, args);          \
 }
 
 #undef DEFINE_EVENT_PRINT
index 0387100..e5e5f48 100644 (file)
@@ -47,10 +47,10 @@ enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
 #endif
 
 #ifdef CONFIG_PERF_EVENTS
-int prof_sysenter_enable(struct ftrace_event_call *call);
-void prof_sysenter_disable(struct ftrace_event_call *call);
-int prof_sysexit_enable(struct ftrace_event_call *call);
-void prof_sysexit_disable(struct ftrace_event_call *call);
+int perf_sysenter_enable(struct ftrace_event_call *call);
+void perf_sysenter_disable(struct ftrace_event_call *call);
+int perf_sysexit_enable(struct ftrace_event_call *call);
+void perf_sysexit_disable(struct ftrace_event_call *call);
 #endif
 
 #endif /* _TRACE_SYSCALL_H */
index fa034d2..0ed46f3 100644 (file)
@@ -259,7 +259,8 @@ static void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
        struct kprobe_insn_page *kip;
 
        list_for_each_entry(kip, &c->pages, list) {
-               long idx = ((long)slot - (long)kip->insns) / c->insn_size;
+               long idx = ((long)slot - (long)kip->insns) /
+                               (c->insn_size * sizeof(kprobe_opcode_t));
                if (idx >= 0 && idx < slots_per_page(c)) {
                        WARN_ON(kip->slot_used[idx] != SLOT_USED);
                        if (dirty) {
index 681bc2e..c927a54 100644 (file)
@@ -3211,8 +3211,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 {
        unsigned long flags;
 
-       trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
-
        if (unlikely(current->lockdep_recursion))
                return;
 
@@ -3220,6 +3218,7 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        check_flags(flags);
 
        current->lockdep_recursion = 1;
+       trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
        __lock_acquire(lock, subclass, trylock, read, check,
                       irqs_disabled_flags(flags), nest_lock, ip, 0);
        current->lockdep_recursion = 0;
@@ -3232,14 +3231,13 @@ void lock_release(struct lockdep_map *lock, int nested,
 {
        unsigned long flags;
 
-       trace_lock_release(lock, nested, ip);
-
        if (unlikely(current->lockdep_recursion))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
        current->lockdep_recursion = 1;
+       trace_lock_release(lock, nested, ip);
        __lock_release(lock, nested, ip);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
@@ -3413,8 +3411,6 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       trace_lock_contended(lock, ip);
-
        if (unlikely(!lock_stat))
                return;
 
@@ -3424,6 +3420,7 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
        raw_local_irq_save(flags);
        check_flags(flags);
        current->lockdep_recursion = 1;
+       trace_lock_contended(lock, ip);
        __lock_contended(lock, ip);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
index 4393b9e..574ee58 100644 (file)
@@ -81,10 +81,6 @@ extern __weak const struct pmu *hw_perf_event_init(struct perf_event *event)
 void __weak hw_perf_disable(void)              { barrier(); }
 void __weak hw_perf_enable(void)               { barrier(); }
 
-void __weak hw_perf_event_setup(int cpu)       { barrier(); }
-void __weak hw_perf_event_setup_online(int cpu)        { barrier(); }
-void __weak hw_perf_event_setup_offline(int cpu)       { barrier(); }
-
 int __weak
 hw_perf_group_sched_in(struct perf_event *group_leader,
               struct perf_cpu_context *cpuctx,
@@ -97,25 +93,15 @@ void __weak perf_event_print_debug(void)    { }
 
 static DEFINE_PER_CPU(int, perf_disable_count);
 
-void __perf_disable(void)
-{
-       __get_cpu_var(perf_disable_count)++;
-}
-
-bool __perf_enable(void)
-{
-       return !--__get_cpu_var(perf_disable_count);
-}
-
 void perf_disable(void)
 {
-       __perf_disable();
-       hw_perf_disable();
+       if (!__get_cpu_var(perf_disable_count)++)
+               hw_perf_disable();
 }
 
 void perf_enable(void)
 {
-       if (__perf_enable())
+       if (!--__get_cpu_var(perf_disable_count))
                hw_perf_enable();
 }
 
@@ -1538,12 +1524,15 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
                 */
                if (interrupts == MAX_INTERRUPTS) {
                        perf_log_throttle(event, 1);
+                       perf_disable();
                        event->pmu->unthrottle(event);
+                       perf_enable();
                }
 
                if (!event->attr.freq || !event->attr.sample_freq)
                        continue;
 
+               perf_disable();
                event->pmu->read(event);
                now = atomic64_read(&event->count);
                delta = now - hwc->freq_count_stamp;
@@ -1551,6 +1540,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
 
                if (delta > 0)
                        perf_adjust_period(event, TICK_NSEC, delta);
+               perf_enable();
        }
        raw_spin_unlock(&ctx->lock);
 }
@@ -1560,9 +1550,6 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
  */
 static void rotate_ctx(struct perf_event_context *ctx)
 {
-       if (!ctx->nr_events)
-               return;
-
        raw_spin_lock(&ctx->lock);
 
        /* Rotate the first entry last of non-pinned groups */
@@ -1575,19 +1562,28 @@ void perf_event_task_tick(struct task_struct *curr)
 {
        struct perf_cpu_context *cpuctx;
        struct perf_event_context *ctx;
+       int rotate = 0;
 
        if (!atomic_read(&nr_events))
                return;
 
        cpuctx = &__get_cpu_var(perf_cpu_context);
-       ctx = curr->perf_event_ctxp;
+       if (cpuctx->ctx.nr_events &&
+           cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
+               rotate = 1;
 
-       perf_disable();
+       ctx = curr->perf_event_ctxp;
+       if (ctx && ctx->nr_events && ctx->nr_events != ctx->nr_active)
+               rotate = 1;
 
        perf_ctx_adjust_freq(&cpuctx->ctx);
        if (ctx)
                perf_ctx_adjust_freq(ctx);
 
+       if (!rotate)
+               return;
+
+       perf_disable();
        cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
        if (ctx)
                task_ctx_sched_out(ctx, EVENT_FLEXIBLE);
@@ -1599,7 +1595,6 @@ void perf_event_task_tick(struct task_struct *curr)
        cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE);
        if (ctx)
                task_ctx_sched_in(curr, EVENT_FLEXIBLE);
-
        perf_enable();
 }
 
@@ -2791,6 +2786,13 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
        return NULL;
 }
 
+#ifdef CONFIG_EVENT_TRACING
+__weak
+void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
+{
+}
+#endif
+
 /*
  * Output
  */
@@ -4318,9 +4320,8 @@ static const struct pmu perf_ops_task_clock = {
 #ifdef CONFIG_EVENT_TRACING
 
 void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
-                         int entry_size)
+                  int entry_size, struct pt_regs *regs)
 {
-       struct pt_regs *regs = get_irq_regs();
        struct perf_sample_data data;
        struct perf_raw_record raw = {
                .size = entry_size,
@@ -4330,12 +4331,9 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
        perf_sample_data_init(&data, addr);
        data.raw = &raw;
 
-       if (!regs)
-               regs = task_pt_regs(current);
-
        /* Trace events already protected against recursion */
        do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
-                               &data, regs);
+                        &data, regs);
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
 
@@ -4351,7 +4349,7 @@ static int perf_tp_event_match(struct perf_event *event,
 
 static void tp_perf_event_destroy(struct perf_event *event)
 {
-       ftrace_profile_disable(event->attr.config);
+       perf_trace_disable(event->attr.config);
 }
 
 static const struct pmu *tp_perf_event_init(struct perf_event *event)
@@ -4365,7 +4363,7 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
                        !capable(CAP_SYS_ADMIN))
                return ERR_PTR(-EPERM);
 
-       if (ftrace_profile_enable(event->attr.config))
+       if (perf_trace_enable(event->attr.config))
                return NULL;
 
        event->destroy = tp_perf_event_destroy;
@@ -5372,18 +5370,26 @@ int perf_event_init_task(struct task_struct *child)
        return ret;
 }
 
+static void __init perf_event_init_all_cpus(void)
+{
+       int cpu;
+       struct perf_cpu_context *cpuctx;
+
+       for_each_possible_cpu(cpu) {
+               cpuctx = &per_cpu(perf_cpu_context, cpu);
+               __perf_event_init_context(&cpuctx->ctx, NULL);
+       }
+}
+
 static void __cpuinit perf_event_init_cpu(int cpu)
 {
        struct perf_cpu_context *cpuctx;
 
        cpuctx = &per_cpu(perf_cpu_context, cpu);
-       __perf_event_init_context(&cpuctx->ctx, NULL);
 
        spin_lock(&perf_resource_lock);
        cpuctx->max_pertask = perf_max_events - perf_reserved_percpu;
        spin_unlock(&perf_resource_lock);
-
-       hw_perf_event_setup(cpu);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -5423,20 +5429,11 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
                perf_event_init_cpu(cpu);
                break;
 
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               hw_perf_event_setup_online(cpu);
-               break;
-
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
                perf_event_exit_cpu(cpu);
                break;
 
-       case CPU_DEAD:
-               hw_perf_event_setup_offline(cpu);
-               break;
-
        default:
                break;
        }
@@ -5454,6 +5451,7 @@ static struct notifier_block __cpuinitdata perf_cpu_nb = {
 
 void __init perf_event_init(void)
 {
+       perf_event_init_all_cpus();
        perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE,
                        (void *)(long)smp_processor_id());
        perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_ONLINE,
index d00c6fe..78edc64 100644 (file)
@@ -52,7 +52,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events.o
 obj-$(CONFIG_EVENT_TRACING) += trace_export.o
 obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
 ifeq ($(CONFIG_PERF_EVENTS),y)
-obj-$(CONFIG_EVENT_TRACING) += trace_event_profile.o
+obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o
 endif
 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
 obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
similarity index 68%
rename from kernel/trace/trace_event_profile.c
rename to kernel/trace/trace_event_perf.c
index c1cc3ab..81f691e 100644 (file)
@@ -1,32 +1,36 @@
 /*
- * trace event based perf counter profiling
+ * trace event based perf event profiling/tracing
  *
  * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
- *
+ * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
  */
 
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include "trace.h"
 
+DEFINE_PER_CPU(struct pt_regs, perf_trace_regs);
+EXPORT_PER_CPU_SYMBOL_GPL(perf_trace_regs);
+
+EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
 
 static char *perf_trace_buf;
 static char *perf_trace_buf_nmi;
 
-typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ;
+typedef typeof(char [PERF_MAX_TRACE_SIZE]) perf_trace_t ;
 
 /* Count the events in use (per event id, not per instance) */
-static int     total_profile_count;
+static int     total_ref_count;
 
-static int ftrace_profile_enable_event(struct ftrace_event_call *event)
+static int perf_trace_event_enable(struct ftrace_event_call *event)
 {
        char *buf;
        int ret = -ENOMEM;
 
-       if (event->profile_count++ > 0)
+       if (event->perf_refcount++ > 0)
                return 0;
 
-       if (!total_profile_count) {
+       if (!total_ref_count) {
                buf = (char *)alloc_percpu(perf_trace_t);
                if (!buf)
                        goto fail_buf;
@@ -40,35 +44,35 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
                rcu_assign_pointer(perf_trace_buf_nmi, buf);
        }
 
-       ret = event->profile_enable(event);
+       ret = event->perf_event_enable(event);
        if (!ret) {
-               total_profile_count++;
+               total_ref_count++;
                return 0;
        }
 
 fail_buf_nmi:
-       if (!total_profile_count) {
+       if (!total_ref_count) {
                free_percpu(perf_trace_buf_nmi);
                free_percpu(perf_trace_buf);
                perf_trace_buf_nmi = NULL;
                perf_trace_buf = NULL;
        }
 fail_buf:
-       event->profile_count--;
+       event->perf_refcount--;
 
        return ret;
 }
 
-int ftrace_profile_enable(int event_id)
+int perf_trace_enable(int event_id)
 {
        struct ftrace_event_call *event;
        int ret = -EINVAL;
 
        mutex_lock(&event_mutex);
        list_for_each_entry(event, &ftrace_events, list) {
-               if (event->id == event_id && event->profile_enable &&
+               if (event->id == event_id && event->perf_event_enable &&
                    try_module_get(event->mod)) {
-                       ret = ftrace_profile_enable_event(event);
+                       ret = perf_trace_event_enable(event);
                        break;
                }
        }
@@ -77,16 +81,16 @@ int ftrace_profile_enable(int event_id)
        return ret;
 }
 
-static void ftrace_profile_disable_event(struct ftrace_event_call *event)
+static void perf_trace_event_disable(struct ftrace_event_call *event)
 {
        char *buf, *nmi_buf;
 
-       if (--event->profile_count > 0)
+       if (--event->perf_refcount > 0)
                return;
 
-       event->profile_disable(event);
+       event->perf_event_disable(event);
 
-       if (!--total_profile_count) {
+       if (!--total_ref_count) {
                buf = perf_trace_buf;
                rcu_assign_pointer(perf_trace_buf, NULL);
 
@@ -104,14 +108,14 @@ static void ftrace_profile_disable_event(struct ftrace_event_call *event)
        }
 }
 
-void ftrace_profile_disable(int event_id)
+void perf_trace_disable(int event_id)
 {
        struct ftrace_event_call *event;
 
        mutex_lock(&event_mutex);
        list_for_each_entry(event, &ftrace_events, list) {
                if (event->id == event_id) {
-                       ftrace_profile_disable_event(event);
+                       perf_trace_event_disable(event);
                        module_put(event->mod);
                        break;
                }
@@ -119,8 +123,8 @@ void ftrace_profile_disable(int event_id)
        mutex_unlock(&event_mutex);
 }
 
-__kprobes void *ftrace_perf_buf_prepare(int size, unsigned short type,
-                                       int *rctxp, unsigned long *irq_flags)
+__kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
+                                      int *rctxp, unsigned long *irq_flags)
 {
        struct trace_entry *entry;
        char *trace_buf, *raw_data;
@@ -161,4 +165,4 @@ err_recursion:
        local_irq_restore(*irq_flags);
        return NULL;
 }
-EXPORT_SYMBOL_GPL(ftrace_perf_buf_prepare);
+EXPORT_SYMBOL_GPL(perf_trace_buf_prepare);
index 3f972ad..beab8bf 100644 (file)
@@ -938,7 +938,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
                trace_create_file("enable", 0644, call->dir, call,
                                  enable);
 
-       if (call->id && call->profile_enable)
+       if (call->id && call->perf_event_enable)
                trace_create_file("id", 0444, call->dir, call,
                                  id);
 
index 505c922..1251e36 100644 (file)
@@ -1214,7 +1214,7 @@ static int set_print_fmt(struct trace_probe *tp)
 #ifdef CONFIG_PERF_EVENTS
 
 /* Kprobe profile handler */
-static __kprobes void kprobe_profile_func(struct kprobe *kp,
+static __kprobes void kprobe_perf_func(struct kprobe *kp,
                                         struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
@@ -1227,11 +1227,11 @@ static __kprobes void kprobe_profile_func(struct kprobe *kp,
        __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
-       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
                     "profile buffer not large enough"))
                return;
 
-       entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags);
+       entry = perf_trace_buf_prepare(size, call->id, &rctx, &irq_flags);
        if (!entry)
                return;
 
@@ -1240,11 +1240,11 @@ static __kprobes void kprobe_profile_func(struct kprobe *kp,
        for (i = 0; i < tp->nr_args; i++)
                entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
 
-       ftrace_perf_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags);
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs);
 }
 
 /* Kretprobe profile handler */
-static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri,
+static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
                                            struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
@@ -1257,11 +1257,11 @@ static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri,
        __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
-       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
                     "profile buffer not large enough"))
                return;
 
-       entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags);
+       entry = perf_trace_buf_prepare(size, call->id, &rctx, &irq_flags);
        if (!entry)
                return;
 
@@ -1271,10 +1271,11 @@ static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri,
        for (i = 0; i < tp->nr_args; i++)
                entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
 
-       ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags);
+       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1,
+                              irq_flags, regs);
 }
 
-static int probe_profile_enable(struct ftrace_event_call *call)
+static int probe_perf_enable(struct ftrace_event_call *call)
 {
        struct trace_probe *tp = (struct trace_probe *)call->data;
 
@@ -1286,7 +1287,7 @@ static int probe_profile_enable(struct ftrace_event_call *call)
                return enable_kprobe(&tp->rp.kp);
 }
 
-static void probe_profile_disable(struct ftrace_event_call *call)
+static void probe_perf_disable(struct ftrace_event_call *call)
 {
        struct trace_probe *tp = (struct trace_probe *)call->data;
 
@@ -1311,7 +1312,7 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
                kprobe_trace_func(kp, regs);
 #ifdef CONFIG_PERF_EVENTS
        if (tp->flags & TP_FLAG_PROFILE)
-               kprobe_profile_func(kp, regs);
+               kprobe_perf_func(kp, regs);
 #endif
        return 0;       /* We don't tweek kernel, so just return 0 */
 }
@@ -1325,7 +1326,7 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
                kretprobe_trace_func(ri, regs);
 #ifdef CONFIG_PERF_EVENTS
        if (tp->flags & TP_FLAG_PROFILE)
-               kretprobe_profile_func(ri, regs);
+               kretprobe_perf_func(ri, regs);
 #endif
        return 0;       /* We don't tweek kernel, so just return 0 */
 }
@@ -1358,8 +1359,8 @@ static int register_probe_event(struct trace_probe *tp)
        call->unregfunc = probe_event_disable;
 
 #ifdef CONFIG_PERF_EVENTS
-       call->profile_enable = probe_profile_enable;
-       call->profile_disable = probe_profile_disable;
+       call->perf_event_enable = probe_perf_enable;
+       call->perf_event_disable = probe_perf_disable;
 #endif
        call->data = tp;
        ret = trace_add_event_call(call);
index cba47d7..33c2a5b 100644 (file)
@@ -428,12 +428,12 @@ core_initcall(init_ftrace_syscalls);
 
 #ifdef CONFIG_PERF_EVENTS
 
-static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls);
-static DECLARE_BITMAP(enabled_prof_exit_syscalls, NR_syscalls);
-static int sys_prof_refcount_enter;
-static int sys_prof_refcount_exit;
+static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls);
+static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls);
+static int sys_perf_refcount_enter;
+static int sys_perf_refcount_exit;
 
-static void prof_syscall_enter(struct pt_regs *regs, long id)
+static void perf_syscall_enter(struct pt_regs *regs, long id)
 {
        struct syscall_metadata *sys_data;
        struct syscall_trace_enter *rec;
@@ -443,7 +443,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
        int size;
 
        syscall_nr = syscall_get_nr(current, regs);
-       if (!test_bit(syscall_nr, enabled_prof_enter_syscalls))
+       if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
                return;
 
        sys_data = syscall_nr_to_meta(syscall_nr);
@@ -455,11 +455,11 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
        size = ALIGN(size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
 
-       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
-                     "profile buffer not large enough"))
+       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
+                     "perf buffer not large enough"))
                return;
 
-       rec = (struct syscall_trace_enter *)ftrace_perf_buf_prepare(size,
+       rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
                                sys_data->enter_event->id, &rctx, &flags);
        if (!rec)
                return;
@@ -467,10 +467,10 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
        rec->nr = syscall_nr;
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
-       ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
 }
 
-int prof_sysenter_enable(struct ftrace_event_call *call)
+int perf_sysenter_enable(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
@@ -478,34 +478,34 @@ int prof_sysenter_enable(struct ftrace_event_call *call)
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
-       if (!sys_prof_refcount_enter)
-               ret = register_trace_sys_enter(prof_syscall_enter);
+       if (!sys_perf_refcount_enter)
+               ret = register_trace_sys_enter(perf_syscall_enter);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall entry trace point");
        } else {
-               set_bit(num, enabled_prof_enter_syscalls);
-               sys_prof_refcount_enter++;
+               set_bit(num, enabled_perf_enter_syscalls);
+               sys_perf_refcount_enter++;
        }
        mutex_unlock(&syscall_trace_lock);
        return ret;
 }
 
-void prof_sysenter_disable(struct ftrace_event_call *call)
+void perf_sysenter_disable(struct ftrace_event_call *call)
 {
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
-       sys_prof_refcount_enter--;
-       clear_bit(num, enabled_prof_enter_syscalls);
-       if (!sys_prof_refcount_enter)
-               unregister_trace_sys_enter(prof_syscall_enter);
+       sys_perf_refcount_enter--;
+       clear_bit(num, enabled_perf_enter_syscalls);
+       if (!sys_perf_refcount_enter)
+               unregister_trace_sys_enter(perf_syscall_enter);
        mutex_unlock(&syscall_trace_lock);
 }
 
-static void prof_syscall_exit(struct pt_regs *regs, long ret)
+static void perf_syscall_exit(struct pt_regs *regs, long ret)
 {
        struct syscall_metadata *sys_data;
        struct syscall_trace_exit *rec;
@@ -515,7 +515,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
        int size;
 
        syscall_nr = syscall_get_nr(current, regs);
-       if (!test_bit(syscall_nr, enabled_prof_exit_syscalls))
+       if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
                return;
 
        sys_data = syscall_nr_to_meta(syscall_nr);
@@ -530,11 +530,11 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
         * Impossible, but be paranoid with the future
         * How to put this check outside runtime?
         */
-       if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
-               "exit event has grown above profile buffer size"))
+       if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
+               "exit event has grown above perf buffer size"))
                return;
 
-       rec = (struct syscall_trace_exit *)ftrace_perf_buf_prepare(size,
+       rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
                                sys_data->exit_event->id, &rctx, &flags);
        if (!rec)
                return;
@@ -542,10 +542,10 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
 
-       ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs);
 }
 
-int prof_sysexit_enable(struct ftrace_event_call *call)
+int perf_sysexit_enable(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
@@ -553,30 +553,30 @@ int prof_sysexit_enable(struct ftrace_event_call *call)
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
-       if (!sys_prof_refcount_exit)
-               ret = register_trace_sys_exit(prof_syscall_exit);
+       if (!sys_perf_refcount_exit)
+               ret = register_trace_sys_exit(perf_syscall_exit);
        if (ret) {
                pr_info("event trace: Could not activate"
                                "syscall exit trace point");
        } else {
-               set_bit(num, enabled_prof_exit_syscalls);
-               sys_prof_refcount_exit++;
+               set_bit(num, enabled_perf_exit_syscalls);
+               sys_perf_refcount_exit++;
        }
        mutex_unlock(&syscall_trace_lock);
        return ret;
 }
 
-void prof_sysexit_disable(struct ftrace_event_call *call)
+void perf_sysexit_disable(struct ftrace_event_call *call)
 {
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
 
        mutex_lock(&syscall_trace_lock);
-       sys_prof_refcount_exit--;
-       clear_bit(num, enabled_prof_exit_syscalls);
-       if (!sys_prof_refcount_exit)
-               unregister_trace_sys_exit(prof_syscall_exit);
+       sys_perf_refcount_exit--;
+       clear_bit(num, enabled_perf_exit_syscalls);
+       if (!sys_perf_refcount_exit)
+               unregister_trace_sys_exit(perf_syscall_exit);
        mutex_unlock(&syscall_trace_lock);
 }
 
index 3dd8853..6c00814 100644 (file)
@@ -284,6 +284,7 @@ static DEFINE_MUTEX(swap_cgroup_mutex);
 struct swap_cgroup_ctrl {
        struct page **map;
        unsigned long length;
+       spinlock_t      lock;
 };
 
 struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
@@ -353,16 +354,22 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
        struct swap_cgroup *sc;
+       unsigned long flags;
+       unsigned short retval;
 
        ctrl = &swap_cgroup_ctrl[type];
 
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       if (cmpxchg(&sc->id, old, new) == old)
-               return old;
+       spin_lock_irqsave(&ctrl->lock, flags);
+       retval = sc->id;
+       if (retval == old)
+               sc->id = new;
        else
-               return 0;
+               retval = 0;
+       spin_unlock_irqrestore(&ctrl->lock, flags);
+       return retval;
 }
 
 /**
@@ -383,13 +390,17 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
        struct page *mappage;
        struct swap_cgroup *sc;
        unsigned short old;
+       unsigned long flags;
 
        ctrl = &swap_cgroup_ctrl[type];
 
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       old = xchg(&sc->id, id);
+       spin_lock_irqsave(&ctrl->lock, flags);
+       old = sc->id;
+       sc->id = id;
+       spin_unlock_irqrestore(&ctrl->lock, flags);
 
        return old;
 }
@@ -441,6 +452,7 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
        mutex_lock(&swap_cgroup_mutex);
        ctrl->length = length;
        ctrl->map = array;
+       spin_lock_init(&ctrl->lock);
        if (swap_cgroup_prepare(type)) {
                /* memory shortage */
                ctrl->map = NULL;
index eb7062d..90a9024 100644 (file)
@@ -40,7 +40,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                        goto out;
 
                mdst = br_mdb_get(br, skb);
-               if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only)
+               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
                        br_multicast_deliver(mdst, skb);
                else
                        br_flood_deliver(br, skb);
index d61e6f7..8dbec83 100644 (file)
 #include <linux/netfilter_bridge.h>
 #include "br_private.h"
 
+static int deliver_clone(const struct net_bridge_port *prev,
+                        struct sk_buff *skb,
+                        void (*__packet_hook)(const struct net_bridge_port *p,
+                                              struct sk_buff *skb));
+
 /* Don't forward packets to originating port or forwarding diasabled */
 static inline int should_deliver(const struct net_bridge_port *p,
                                 const struct sk_buff *skb)
@@ -94,17 +99,22 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 }
 
 /* called with rcu_read_lock */
-void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
+void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
 {
        if (should_deliver(to, skb)) {
-               __br_forward(to, skb);
+               if (skb0)
+                       deliver_clone(to, skb, __br_forward);
+               else
+                       __br_forward(to, skb);
                return;
        }
 
-       kfree_skb(skb);
+       if (!skb0)
+               kfree_skb(skb);
 }
 
-static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
+static int deliver_clone(const struct net_bridge_port *prev,
+                        struct sk_buff *skb,
                         void (*__packet_hook)(const struct net_bridge_port *p,
                                               struct sk_buff *skb))
 {
index 53b3985..d74d570 100644 (file)
@@ -70,7 +70,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
 
        if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb);
-               if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) {
+               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
                        if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
@@ -90,7 +90,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
 
        if (skb) {
                if (dst)
-                       br_forward(dst->dst, skb);
+                       br_forward(dst->dst, skb, skb2);
                else
                        br_flood_forward(br, skb, skb2);
        }
index fd96a8d..6980625 100644 (file)
@@ -49,22 +49,23 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(
 static struct net_bridge_mdb_entry *br_mdb_ip_get(
        struct net_bridge_mdb_htable *mdb, __be32 dst)
 {
+       if (!mdb)
+               return NULL;
+
        return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));
 }
 
 struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
                                        struct sk_buff *skb)
 {
-       struct net_bridge_mdb_htable *mdb = br->mdb;
-
-       if (!mdb || br->multicast_disabled)
+       if (br->multicast_disabled)
                return NULL;
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                if (BR_INPUT_SKB_CB(skb)->igmp)
                        break;
-               return br_mdb_ip_get(mdb, ip_hdr(skb)->daddr);
+               return br_mdb_ip_get(br->mdb, ip_hdr(skb)->daddr);
        }
 
        return NULL;
@@ -851,8 +852,8 @@ static int br_multicast_query(struct net_bridge *br,
                if (ih3->nsrcs)
                        goto out;
 
-               max_delay = ih3->code ? 1 :
-                           IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE);
+               max_delay = ih3->code ?
+                           IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
        if (!group)
@@ -990,7 +991,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 
                err = pskb_trim_rcsum(skb2, len);
                if (err)
-                       return err;
+                       goto err_out;
        }
 
        len -= ip_hdrlen(skb2);
@@ -1012,7 +1013,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
        case CHECKSUM_NONE:
                skb2->csum = 0;
                if (skb_checksum_complete(skb2))
-                       return -EINVAL;
+                       goto out;
        }
 
        err = 0;
@@ -1039,6 +1040,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 
 out:
        __skb_push(skb2, offset);
+err_out:
        if (skb2 != skb)
                kfree_skb(skb2);
        return err;
index fef0384..846d7d1 100644 (file)
@@ -206,12 +206,20 @@ struct net_bridge
 
 struct br_input_skb_cb {
        struct net_device *brdev;
+#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
        int igmp;
        int mrouters_only;
+#endif
 };
 
 #define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
 
+#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+# define BR_INPUT_SKB_CB_MROUTERS_ONLY(__skb)  (BR_INPUT_SKB_CB(__skb)->mrouters_only)
+#else
+# define BR_INPUT_SKB_CB_MROUTERS_ONLY(__skb)  (0)
+#endif
+
 extern struct notifier_block br_device_notifier;
 extern const u8 br_group_address[ETH_ALEN];
 
@@ -252,7 +260,7 @@ extern void br_deliver(const struct net_bridge_port *to,
                struct sk_buff *skb);
 extern int br_dev_queue_push_xmit(struct sk_buff *skb);
 extern void br_forward(const struct net_bridge_port *to,
-               struct sk_buff *skb);
+               struct sk_buff *skb, struct sk_buff *skb0);
 extern int br_forward_finish(struct sk_buff *skb);
 extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
 extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
index 7aa6972..d4ec38f 100644 (file)
@@ -735,7 +735,7 @@ int netpoll_setup(struct netpoll *np)
                npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
                if (!npinfo) {
                        err = -ENOMEM;
-                       goto release;
+                       goto put;
                }
 
                npinfo->rx_flags = 0;
@@ -845,7 +845,7 @@ int netpoll_setup(struct netpoll *np)
 
                kfree(npinfo);
        }
-
+put:
        dev_put(ndev);
        return err;
 }
index b195c4f..4071eaf 100644 (file)
@@ -998,11 +998,11 @@ static struct inet_protosw dccp_v4_protosw = {
 
 static int __net_init dccp_v4_init_net(struct net *net)
 {
-       int err;
+       if (dccp_hashinfo.bhash == NULL)
+               return -ESOCKTNOSUPPORT;
 
-       err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET,
-                                  SOCK_DCCP, IPPROTO_DCCP, net);
-       return err;
+       return inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET,
+                                   SOCK_DCCP, IPPROTO_DCCP, net);
 }
 
 static void __net_exit dccp_v4_exit_net(struct net *net)
index 1aec634..af3394d 100644 (file)
@@ -1191,11 +1191,11 @@ static struct inet_protosw dccp_v6_protosw = {
 
 static int __net_init dccp_v6_init_net(struct net *net)
 {
-       int err;
+       if (dccp_hashinfo.bhash == NULL)
+               return -ESOCKTNOSUPPORT;
 
-       err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
-                                  SOCK_DCCP, IPPROTO_DCCP, net);
-       return err;
+       return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
+                                   SOCK_DCCP, IPPROTO_DCCP, net);
 }
 
 static void __net_exit dccp_v6_exit_net(struct net *net)
index 0ef7061..aa4cef3 100644 (file)
@@ -1036,7 +1036,7 @@ static int __init dccp_init(void)
                     FIELD_SIZEOF(struct sk_buff, cb));
        rc = percpu_counter_init(&dccp_orphan_count, 0);
        if (rc)
-               goto out;
+               goto out_fail;
        rc = -ENOBUFS;
        inet_hashinfo_init(&dccp_hashinfo);
        dccp_hashinfo.bind_bucket_cachep =
@@ -1125,8 +1125,9 @@ static int __init dccp_init(void)
                goto out_sysctl_exit;
 
        dccp_timestamping_init();
-out:
-       return rc;
+
+       return 0;
+
 out_sysctl_exit:
        dccp_sysctl_exit();
 out_ackvec_exit:
@@ -1135,18 +1136,19 @@ out_free_dccp_mib:
        dccp_mib_exit();
 out_free_dccp_bhash:
        free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
-       dccp_hashinfo.bhash = NULL;
 out_free_dccp_locks:
        inet_ehash_locks_free(&dccp_hashinfo);
 out_free_dccp_ehash:
        free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
-       dccp_hashinfo.ehash = NULL;
 out_free_bind_bucket_cachep:
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
-       dccp_hashinfo.bind_bucket_cachep = NULL;
 out_free_percpu:
        percpu_counter_destroy(&dccp_orphan_count);
-       goto out;
+out_fail:
+       dccp_hashinfo.bhash = NULL;
+       dccp_hashinfo.ehash = NULL;
+       dccp_hashinfo.bind_bucket_cachep = NULL;
+       return rc;
 }
 
 static void __exit dccp_fini(void)
index d9b4024..a770df2 100644 (file)
@@ -932,10 +932,8 @@ static void rt_secret_rebuild_oneshot(struct net *net)
 {
        del_timer_sync(&net->ipv4.rt_secret_timer);
        rt_cache_invalidate(net);
-       if (ip_rt_secret_interval) {
-               net->ipv4.rt_secret_timer.expires += ip_rt_secret_interval;
-               add_timer(&net->ipv4.rt_secret_timer);
-       }
+       if (ip_rt_secret_interval)
+               mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval);
 }
 
 static void rt_emergency_hash_rebuild(struct net *net)
@@ -3103,22 +3101,20 @@ static void rt_secret_reschedule(int old)
        rtnl_lock();
        for_each_net(net) {
                int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
+               long time;
 
                if (!new)
                        continue;
 
                if (deleted) {
-                       long time = net->ipv4.rt_secret_timer.expires - jiffies;
+                       time = net->ipv4.rt_secret_timer.expires - jiffies;
 
                        if (time <= 0 || (time += diff) <= 0)
                                time = 0;
-
-                       net->ipv4.rt_secret_timer.expires = time;
                } else
-                       net->ipv4.rt_secret_timer.expires = new;
+                       time = new;
 
-               net->ipv4.rt_secret_timer.expires += jiffies;
-               add_timer(&net->ipv4.rt_secret_timer);
+               mod_timer(&net->ipv4.rt_secret_timer, jiffies + time);
        }
        rtnl_unlock();
 }
index c597cc5..5c6ae0c 100644 (file)
@@ -107,8 +107,7 @@ static void phonet_device_destroy(struct net_device *dev)
        if (pnd) {
                u8 addr;
 
-               for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
-                       addr = find_next_bit(pnd->addrs, 64, 1+addr))
+               for_each_set_bit(addr, pnd->addrs, 64)
                        phonet_address_notify(RTM_DELADDR, dev, addr);
                kfree(pnd);
        }
index 2e6c7eb..fe2e708 100644 (file)
@@ -141,8 +141,7 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
                        continue;
 
                addr_idx = 0;
-               for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
-                       addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
+               for_each_set_bit(addr, pnd->addrs, 64) {
                        if (addr_idx++ < addr_start_idx)
                                continue;
 
index 75ab08e..e4839c0 100644 (file)
@@ -548,8 +548,6 @@ static int xs_udp_send_request(struct rpc_task *task)
                /* Still some bytes left; set up for a retry later. */
                status = -EAGAIN;
        }
-       if (!transport->sock)
-               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -569,7 +567,7 @@ static int xs_udp_send_request(struct rpc_task *task)
                 * prompts ECONNREFUSED. */
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
        }
-out:
+
        return status;
 }
 
@@ -651,8 +649,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
                status = -EAGAIN;
                break;
        }
-       if (!transport->sock)
-               goto out;
 
        switch (status) {
        case -ENOTSOCK:
@@ -672,7 +668,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
        case -ENOTCONN:
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
        }
-out:
+
        return status;
 }
 
index 414fc34..8dea665 100644 (file)
@@ -153,11 +153,11 @@ void tipc_ref_table_stop(void)
 
 u32 tipc_ref_acquire(void *object, spinlock_t **lock)
 {
-       struct reference *entry;
        u32 index;
        u32 index_mask;
        u32 next_plus_upper;
        u32 ref;
+       struct reference *entry = NULL;
 
        if (!object) {
                err("Attempt to acquire reference to non-existent object\n");
@@ -175,30 +175,36 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
                index = tipc_ref_table.first_free;
                entry = &(tipc_ref_table.entries[index]);
                index_mask = tipc_ref_table.index_mask;
-               /* take lock in case a previous user of entry still holds it */
-               spin_lock_bh(&entry->lock);
                next_plus_upper = entry->ref;
                tipc_ref_table.first_free = next_plus_upper & index_mask;
                ref = (next_plus_upper & ~index_mask) + index;
-               entry->ref = ref;
-               entry->object = object;
-               *lock = &entry->lock;
        }
        else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
                index = tipc_ref_table.init_point++;
                entry = &(tipc_ref_table.entries[index]);
                spin_lock_init(&entry->lock);
-               spin_lock_bh(&entry->lock);
                ref = tipc_ref_table.start_mask + index;
-               entry->ref = ref;
-               entry->object = object;
-               *lock = &entry->lock;
        }
        else {
                ref = 0;
        }
        write_unlock_bh(&ref_table_lock);
 
+       /*
+        * Grab the lock so no one else can modify this entry
+        * While we assign its ref value & object pointer
+        */
+       if (entry) {
+               spin_lock_bh(&entry->lock);
+               entry->ref = ref;
+               entry->object = object;
+               *lock = &entry->lock;
+               /*
+                * keep it locked, the caller is responsible
+                * for unlocking this when they're done with it
+                */
+       }
+
        return ref;
 }
 
index c798746..e85789e 100644 (file)
@@ -1631,8 +1631,6 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
        }
 
        semitones = bend / 100;
-       if (semitones > 99)
-               semitones = 99;
        cents = bend % 100;
 
        amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000;
index 5bd7cf4..0e76ac2 100644 (file)
@@ -1806,6 +1806,8 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
                item->nid = nid;
                return 0;
        }
+       printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n",
+              kctl->id.name, kctl->id.index, index);
        return -EINVAL;
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_nid);
@@ -2884,7 +2886,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
        list_for_each_entry(codec, &bus->codec_list, list) {
                int err = snd_hda_codec_build_controls(codec);
                if (err < 0) {
-                       printk(KERN_ERR "hda_codec: cannot build controls"
+                       printk(KERN_ERR "hda_codec: cannot build controls "
                               "for #%d (error %d)\n", codec->addr, err);
                        err = snd_hda_codec_reset(codec);
                        if (err < 0) {
index da1ac90..8b29156 100644 (file)
@@ -2271,6 +2271,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
        {}
 };
 
@@ -2378,6 +2379,13 @@ static void __devinit check_msi(struct azx *chip)
                       "hda_intel: msi for device %04x:%04x set to %d\n",
                       q->subvendor, q->subdevice, q->value);
                chip->msi = q->value;
+               return;
+       }
+
+       /* NVidia chipsets seem to cause troubles with MSI */
+       if (chip->driver_type == AZX_DRIVER_NVIDIA) {
+               printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n");
+               chip->msi = 0;
        }
 }
 
@@ -2706,6 +2714,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
        /* PCH */
        { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
        /* CPT */
        { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
        /* SCH */
index 3a83719..4ec5763 100644 (file)
@@ -6477,7 +6477,7 @@ static struct alc_config_preset alc260_presets[] = {
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
                .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-               .adc_nids = alc260_adc_nids,
+               .adc_nids = alc260_dual_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
@@ -9195,6 +9195,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
@@ -9204,6 +9205,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
 
@@ -9235,7 +9237,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
        SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
        SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
-       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
+       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
 
        {}
 };
index bdd3b7e..bd498d4 100644 (file)
@@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
 DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
 DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
 
+# Make the path relative to DESTDIR, not prefix
+ifndef DESTDIR
 prefix?=$(HOME)
+endif
 bindir?=$(prefix)/bin
 htmldir?=$(prefix)/share/doc/perf-doc
 pdfdir?=$(prefix)/share/doc/perf-doc
@@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man
 man1dir=$(mandir)/man1
 man5dir=$(mandir)/man5
 man7dir=$(mandir)/man7
-# DESTDIR=
 
 ASCIIDOC=asciidoc
 ASCIIDOC_EXTRA = --unsafe
index 2d53738..8a8f52d 100644 (file)
@@ -216,7 +216,10 @@ STRIP ?= strip
 # runtime figures out where they are based on the path to the executable.
 # This can help installing the suite in a relocatable way.
 
+# Make the path relative to DESTDIR, not to prefix
+ifndef DESTDIR
 prefix = $(HOME)
+endif
 bindir_relative = bin
 bindir = $(prefix)/$(bindir_relative)
 mandir = share/man
@@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc
 ETC_PERFCONFIG = etc/perfconfig
 endif
 lib = lib
-# DESTDIR=
 
 export prefix bindir sharedir sysconfdir
 
@@ -387,6 +389,7 @@ LIB_H += util/thread.h
 LIB_H += util/trace-event.h
 LIB_H += util/probe-finder.h
 LIB_H += util/probe-event.h
+LIB_H += util/cpumap.h
 
 LIB_OBJS += util/abspath.o
 LIB_OBJS += util/alias.o
@@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o
 LIB_OBJS += util/hist.o
 LIB_OBJS += util/probe-event.o
 LIB_OBJS += util/util.o
+LIB_OBJS += util/cpumap.o
 
 BUILTIN_OBJS += builtin-annotate.o
 
index 5ec5de9..6ad7148 100644 (file)
@@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
                return 0;
        }
 
-       he = __perf_session__add_hist_entry(self, al, NULL, count, &hit);
+       he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit);
        if (he == NULL)
                return -ENOMEM;
 
@@ -564,8 +564,8 @@ static int __cmd_annotate(void)
        if (verbose > 2)
                dsos__fprintf(stdout);
 
-       perf_session__collapse_resort(session);
-       perf_session__output_resort(session, session->event_total[0]);
+       perf_session__collapse_resort(&session->hists);
+       perf_session__output_resort(&session->hists, session->event_total[0]);
        perf_session__find_annotations(session);
 out_delete:
        perf_session__delete(session);
index 18b3f50..1ea15d8 100644 (file)
@@ -26,7 +26,8 @@ static int perf_session__add_hist_entry(struct perf_session *self,
                                        struct addr_location *al, u64 count)
 {
        bool hit;
-       struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
+       struct hist_entry *he = __perf_session__add_hist_entry(&self->hists,
+                                                              al, NULL,
                                                               count, &hit);
        if (he == NULL)
                return -ENOMEM;
@@ -114,7 +115,7 @@ static void perf_session__resort_hist_entries(struct perf_session *self)
 
 static void perf_session__set_hist_entries_positions(struct perf_session *self)
 {
-       perf_session__output_resort(self, self->events_stats.total);
+       perf_session__output_resort(&self->hists, self->events_stats.total);
        perf_session__resort_hist_entries(self);
 }
 
@@ -166,13 +167,15 @@ static int __cmd_diff(void)
                        goto out_delete;
        }
 
-       perf_session__output_resort(session[1], session[1]->events_stats.total);
+       perf_session__output_resort(&session[1]->hists,
+                                   session[1]->events_stats.total);
        if (show_displacement)
                perf_session__set_hist_entries_positions(session[0]);
 
        perf_session__match_hists(session[0], session[1]);
-       perf_session__fprintf_hists(session[1], session[0],
-                                   show_displacement, stdout);
+       perf_session__fprintf_hists(&session[1]->hists, session[0],
+                                   show_displacement, stdout,
+                                   session[1]->events_stats.total);
 out_delete:
        for (i = 0; i < 2; ++i)
                perf_session__delete(session[i]);
index 771533c..3b8b638 100644 (file)
@@ -22,6 +22,7 @@
 #include "util/debug.h"
 #include "util/session.h"
 #include "util/symbol.h"
+#include "util/cpumap.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -244,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid)
 
        attr->sample_type       |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
+       if (nr_counters > 1)
+               attr->sample_type |= PERF_SAMPLE_ID;
+
        if (freq) {
                attr->sample_type       |= PERF_SAMPLE_PERIOD;
                attr->freq              = 1;
@@ -391,6 +395,9 @@ static int process_buildids(void)
 {
        u64 size = lseek(output, 0, SEEK_CUR);
 
+       if (size == 0)
+               return 0;
+
        session->fd = output;
        return __perf_session__process_events(session, post_processing_offset,
                                              size - post_processing_offset,
@@ -418,9 +425,6 @@ static int __cmd_record(int argc, const char **argv)
        char buf;
 
        page_size = sysconf(_SC_PAGE_SIZE);
-       nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
-       assert(nr_cpus <= MAX_NR_CPUS);
-       assert(nr_cpus >= 0);
 
        atexit(sig_atexit);
        signal(SIGCHLD, sig_handler);
@@ -544,8 +548,9 @@ static int __cmd_record(int argc, const char **argv)
        if ((!system_wide && !inherit) || profile_cpu != -1) {
                open_counters(profile_cpu, target_pid);
        } else {
+               nr_cpus = read_cpu_map();
                for (i = 0; i < nr_cpus; i++)
-                       open_counters(i, target_pid);
+                       open_counters(cpumap[i], target_pid);
        }
 
        if (file_new) {
index cfc655d..f815de2 100644 (file)
@@ -45,28 +45,71 @@ static char         *pretty_printing_style = default_pretty_printing_style;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
+static struct event_stat_id *get_stats(struct perf_session *self,
+                                      u64 event_stream, u32 type, u64 config)
+{
+       struct rb_node **p = &self->stats_by_id.rb_node;
+       struct rb_node *parent = NULL;
+       struct event_stat_id *iter, *new;
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct event_stat_id, rb_node);
+               if (iter->config == config)
+                       return iter;
+
+
+               if (config > iter->config)
+                       p = &(*p)->rb_right;
+               else
+                       p = &(*p)->rb_left;
+       }
+
+       new = malloc(sizeof(struct event_stat_id));
+       if (new == NULL)
+               return NULL;
+       memset(new, 0, sizeof(struct event_stat_id));
+       new->event_stream = event_stream;
+       new->config = config;
+       new->type = type;
+       rb_link_node(&new->rb_node, parent, p);
+       rb_insert_color(&new->rb_node, &self->stats_by_id);
+       return new;
+}
+
 static int perf_session__add_hist_entry(struct perf_session *self,
                                        struct addr_location *al,
-                                       struct ip_callchain *chain, u64 count)
+                                       struct sample_data *data)
 {
        struct symbol **syms = NULL, *parent = NULL;
        bool hit;
        struct hist_entry *he;
+       struct event_stat_id *stats;
+       struct perf_event_attr *attr;
 
-       if ((sort__has_parent || symbol_conf.use_callchain) && chain)
+       if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain)
                syms = perf_session__resolve_callchain(self, al->thread,
-                                                      chain, &parent);
-       he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
+                                                      data->callchain, &parent);
+
+       attr = perf_header__find_attr(data->id, &self->header);
+       if (attr)
+               stats = get_stats(self, data->id, attr->type, attr->config);
+       else
+               stats = get_stats(self, data->id, 0, 0);
+       if (stats == NULL)
+               return -ENOMEM;
+       he = __perf_session__add_hist_entry(&stats->hists, al, parent,
+                                           data->period, &hit);
        if (he == NULL)
                return -ENOMEM;
 
        if (hit)
-               he->count += count;
+               he->count += data->period;
 
        if (symbol_conf.use_callchain) {
                if (!hit)
                        callchain_init(&he->callchain);
-               append_chain(&he->callchain, chain, syms);
+               append_chain(&he->callchain, data->callchain, syms);
                free(syms);
        }
 
@@ -86,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
        return 0;
 }
 
+static int add_event_total(struct perf_session *session,
+                          struct sample_data *data,
+                          struct perf_event_attr *attr)
+{
+       struct event_stat_id *stats;
+
+       if (attr)
+               stats = get_stats(session, data->id, attr->type, attr->config);
+       else
+               stats = get_stats(session, data->id, 0, 0);
+
+       if (!stats)
+               return -ENOMEM;
+
+       stats->stats.total += data->period;
+       session->events_stats.total += data->period;
+       return 0;
+}
+
 static int process_sample_event(event_t *event, struct perf_session *session)
 {
        struct sample_data data = { .period = 1, };
        struct addr_location al;
+       struct perf_event_attr *attr;
 
        event__parse_sample(event, session->sample_type, &data);
 
@@ -123,12 +186,18 @@ static int process_sample_event(event_t *event, struct perf_session *session)
        if (al.filtered || (hide_unresolved && al.sym == NULL))
                return 0;
 
-       if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
+       if (perf_session__add_hist_entry(session, &al, &data)) {
                pr_debug("problem incrementing symbol count, skipping event\n");
                return -1;
        }
 
-       session->events_stats.total += data.period;
+       attr = perf_header__find_attr(data.id, &session->header);
+
+       if (add_event_total(session, &data, attr)) {
+               pr_debug("problem adding event count\n");
+               return -1;
+       }
+
        return 0;
 }
 
@@ -197,6 +266,7 @@ static int __cmd_report(void)
 {
        int ret = -EINVAL;
        struct perf_session *session;
+       struct rb_node *next;
 
        session = perf_session__new(input_name, O_RDONLY, force);
        if (session == NULL)
@@ -224,10 +294,28 @@ static int __cmd_report(void)
        if (verbose > 2)
                dsos__fprintf(stdout);
 
-       perf_session__collapse_resort(session);
-       perf_session__output_resort(session, session->events_stats.total);
-       fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total);
-       perf_session__fprintf_hists(session, NULL, false, stdout);
+       next = rb_first(&session->stats_by_id);
+       while (next) {
+               struct event_stat_id *stats;
+
+               stats = rb_entry(next, struct event_stat_id, rb_node);
+               perf_session__collapse_resort(&stats->hists);
+               perf_session__output_resort(&stats->hists, stats->stats.total);
+               if (rb_first(&session->stats_by_id) ==
+                   rb_last(&session->stats_by_id))
+                       fprintf(stdout, "# Samples: %Ld\n#\n",
+                               stats->stats.total);
+               else
+                       fprintf(stdout, "# Samples: %Ld %s\n#\n",
+                               stats->stats.total,
+                               __event_name(stats->type, stats->config));
+
+               perf_session__fprintf_hists(&stats->hists, NULL, false, stdout,
+                                           stats->stats.total);
+               fprintf(stdout, "\n\n");
+               next = rb_next(&stats->rb_node);
+       }
+
        if (sort_order == default_sort_order &&
            parent_pattern == default_parent_pattern)
                fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
index e8c85d5..95db31c 100644 (file)
@@ -45,6 +45,7 @@
 #include "util/event.h"
 #include "util/debug.h"
 #include "util/header.h"
+#include "util/cpumap.h"
 
 #include <sys/prctl.h>
 #include <math.h>
@@ -151,7 +152,7 @@ static void create_perf_stat_counter(int counter, int pid)
                unsigned int cpu;
 
                for (cpu = 0; cpu < nr_cpus; cpu++) {
-                       fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0);
+                       fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0);
                        if (fd[cpu][counter] < 0 && verbose)
                                fprintf(stderr, ERR_PERF_OPEN, counter,
                                        fd[cpu][counter], strerror(errno));
@@ -519,9 +520,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
                nr_counters = ARRAY_SIZE(default_attrs);
        }
 
-       nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
-       assert(nr_cpus <= MAX_NR_CPUS);
-       assert((int)nr_cpus >= 0);
+       if (system_wide)
+               nr_cpus = read_cpu_map();
+       else
+               nr_cpus = 1;
 
        /*
         * We dont want to block the signals - that would cause
index 31f2e59..0b719e3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/rbtree.h>
 #include "util/parse-options.h"
 #include "util/parse-events.h"
+#include "util/cpumap.h"
 
 #include "util/debug.h"
 
@@ -1123,7 +1124,7 @@ static void start_counter(int i, int counter)
 
        cpu = profile_cpu;
        if (target_pid == -1 && profile_cpu == -1)
-               cpu = i;
+               cpu = cpumap[i];
 
        attr = attrs + counter;
 
@@ -1347,12 +1348,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
                attrs[counter].sample_period = default_interval;
        }
 
-       nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
-       assert(nr_cpus <= MAX_NR_CPUS);
-       assert(nr_cpus >= 0);
-
        if (target_pid != -1 || profile_cpu != -1)
                nr_cpus = 1;
+       else
+               nr_cpus = read_cpu_map();
 
        get_term_dimensions(&winsize);
        if (print_entries == 0) {
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644 (file)
index 0000000..4e01490
--- /dev/null
@@ -0,0 +1,59 @@
+#include "util.h"
+#include "../perf.h"
+#include "cpumap.h"
+#include <assert.h>
+#include <stdio.h>
+
+int cpumap[MAX_NR_CPUS];
+
+static int default_cpu_map(void)
+{
+       int nr_cpus, i;
+
+       nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+       assert(nr_cpus <= MAX_NR_CPUS);
+       assert((int)nr_cpus >= 0);
+
+       for (i = 0; i < nr_cpus; ++i)
+               cpumap[i] = i;
+
+       return nr_cpus;
+}
+
+int read_cpu_map(void)
+{
+       FILE *onlnf;
+       int nr_cpus = 0;
+       int n, cpu, prev;
+       char sep;
+
+       onlnf = fopen("/sys/devices/system/cpu/online", "r");
+       if (!onlnf)
+               return default_cpu_map();
+
+       sep = 0;
+       prev = -1;
+       for (;;) {
+               n = fscanf(onlnf, "%u%c", &cpu, &sep);
+               if (n <= 0)
+                       break;
+               if (prev >= 0) {
+                       assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
+                       while (++prev < cpu)
+                               cpumap[nr_cpus++] = prev;
+               }
+               assert (nr_cpus < MAX_NR_CPUS);
+               cpumap[nr_cpus++] = cpu;
+               if (n == 2 && sep == '-')
+                       prev = cpu;
+               else
+                       prev = -1;
+               if (n == 1 || sep == '\n')
+                       break;
+       }
+       fclose(onlnf);
+       if (nr_cpus > 0)
+               return nr_cpus;
+
+       return default_cpu_map();
+}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644 (file)
index 0000000..86c78bb
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __PERF_CPUMAP_H
+#define __PERF_CPUMAP_H
+
+extern int read_cpu_map(void);
+extern int cpumap[];
+
+#endif /* __PERF_CPUMAP_H */
index 50a7132..a33b949 100644 (file)
@@ -99,6 +99,15 @@ struct events_stats {
        u64 lost;
 };
 
+struct event_stat_id {
+       struct rb_node          rb_node;
+       struct rb_root          hists;
+       struct events_stats     stats;
+       u64                     config;
+       u64                     event_stream;
+       u32                     type;
+};
+
 void event__print_totals(void);
 
 struct perf_session;
index 44408c2..2be33c7 100644 (file)
@@ -12,12 +12,12 @@ struct callchain_param      callchain_param = {
  * histogram, sorted on item, collects counts
  */
 
-struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
+struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
                                                  struct addr_location *al,
                                                  struct symbol *sym_parent,
                                                  u64 count, bool *hit)
 {
-       struct rb_node **p = &self->hists.rb_node;
+       struct rb_node **p = &hists->rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *he;
        struct hist_entry entry = {
@@ -53,7 +53,7 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
                return NULL;
        *he = entry;
        rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &self->hists);
+       rb_insert_color(&he->rb_node, hists);
        *hit = false;
        return he;
 }
@@ -130,7 +130,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
        rb_insert_color(&he->rb_node, root);
 }
 
-void perf_session__collapse_resort(struct perf_session *self)
+void perf_session__collapse_resort(struct rb_root *hists)
 {
        struct rb_root tmp;
        struct rb_node *next;
@@ -140,17 +140,17 @@ void perf_session__collapse_resort(struct perf_session *self)
                return;
 
        tmp = RB_ROOT;
-       next = rb_first(&self->hists);
+       next = rb_first(hists);
 
        while (next) {
                n = rb_entry(next, struct hist_entry, rb_node);
                next = rb_next(&n->rb_node);
 
-               rb_erase(&n->rb_node, &self->hists);
+               rb_erase(&n->rb_node, hists);
                collapse__insert_entry(&tmp, n);
        }
 
-       self->hists = tmp;
+       *hists = tmp;
 }
 
 /*
@@ -183,7 +183,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,
        rb_insert_color(&he->rb_node, root);
 }
 
-void perf_session__output_resort(struct perf_session *self, u64 total_samples)
+void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
 {
        struct rb_root tmp;
        struct rb_node *next;
@@ -194,18 +194,18 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples)
                total_samples * (callchain_param.min_percent / 100);
 
        tmp = RB_ROOT;
-       next = rb_first(&self->hists);
+       next = rb_first(hists);
 
        while (next) {
                n = rb_entry(next, struct hist_entry, rb_node);
                next = rb_next(&n->rb_node);
 
-               rb_erase(&n->rb_node, &self->hists);
+               rb_erase(&n->rb_node, hists);
                perf_session__insert_output_hist_entry(&tmp, n,
                                                       min_callchain_hits);
        }
 
-       self->hists = tmp;
+       *hists = tmp;
 }
 
 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -456,10 +456,10 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
 }
 
 static size_t hist_entry__fprintf(struct hist_entry *self,
-                                 struct perf_session *session,
                                  struct perf_session *pair_session,
                                  bool show_displacement,
-                                 long displacement, FILE *fp)
+                                 long displacement, FILE *fp,
+                                 u64 session_total)
 {
        struct sort_entry *se;
        u64 count, total;
@@ -474,7 +474,7 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
                total = pair_session->events_stats.total;
        } else {
                count = self->count;
-               total = session->events_stats.total;
+               total = session_total;
        }
 
        if (total)
@@ -496,8 +496,8 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
 
                if (total > 0)
                        old_percent = (count * 100.0) / total;
-               if (session->events_stats.total > 0)
-                       new_percent = (self->count * 100.0) / session->events_stats.total;
+               if (session_total > 0)
+                       new_percent = (self->count * 100.0) / session_total;
 
                diff = new_percent - old_percent;
 
@@ -544,16 +544,17 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
                        left_margin -= thread__comm_len(self->thread);
                }
 
-               hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
+               hist_entry_callchain__fprintf(fp, self, session_total,
                                              left_margin);
        }
 
        return ret;
 }
 
-size_t perf_session__fprintf_hists(struct perf_session *self,
+size_t perf_session__fprintf_hists(struct rb_root *hists,
                                   struct perf_session *pair,
-                                  bool show_displacement, FILE *fp)
+                                  bool show_displacement, FILE *fp,
+                                  u64 session_total)
 {
        struct sort_entry *se;
        struct rb_node *nd;
@@ -641,7 +642,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
        fprintf(fp, "\n#\n");
 
 print_entries:
-       for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
 
                if (show_displacement) {
@@ -652,8 +653,13 @@ print_entries:
                                displacement = 0;
                        ++position;
                }
-               ret += hist_entry__fprintf(h, self, pair, show_displacement,
-                                          displacement, fp);
+               ret += hist_entry__fprintf(h, pair, show_displacement,
+                                          displacement, fp, session_total);
+               if (h->map == NULL && verbose > 1) {
+                       __map_groups__fprintf_maps(&h->thread->mg,
+                                                  MAP__FUNCTION, fp);
+                       fprintf(fp, "%.10s end\n", graph_dotted_line);
+               }
        }
 
        free(rem_sq_bracket);
index e5f99b2..16f360c 100644 (file)
@@ -10,8 +10,9 @@ struct perf_session;
 struct hist_entry;
 struct addr_location;
 struct symbol;
+struct rb_root;
 
-struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
+struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
                                                  struct addr_location *al,
                                                  struct symbol *parent,
                                                  u64 count, bool *hit);
@@ -19,9 +20,10 @@ extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
 extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
 void hist_entry__free(struct hist_entry *);
 
-void perf_session__output_resort(struct perf_session *self, u64 total_samples);
-void perf_session__collapse_resort(struct perf_session *self);
-size_t perf_session__fprintf_hists(struct perf_session *self,
+void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
+void perf_session__collapse_resort(struct rb_root *hists);
+size_t perf_session__fprintf_hists(struct rb_root *hists,
                                   struct perf_session *pair,
-                                  bool show_displacement, FILE *fp);
+                                  bool show_displacement, FILE *fp,
+                                  u64 session_total);
 #endif /* __PERF_HIST_H */
index e77dc88..1e6c65e 100644 (file)
@@ -169,7 +169,7 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
 {
        Dwarf_Files *files;
        size_t nfiles, i;
-       const char *src;
+       const char *src = NULL;
        int ret;
 
        if (!fname)
index 0de7258..eed1cb8 100644 (file)
@@ -70,6 +70,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
 
        memcpy(self->filename, filename, len);
        self->threads = RB_ROOT;
+       self->stats_by_id = RB_ROOT;
        self->last_match = NULL;
        self->mmap_window = 32;
        self->cwd = NULL;
index 31950fc..5c33417 100644 (file)
@@ -20,6 +20,7 @@ struct perf_session {
        struct thread           *last_match;
        struct map              *vmlinux_maps[MAP__NR_TYPES];
        struct events_stats     events_stats;
+       struct rb_root          stats_by_id;
        unsigned long           event_total[PERF_RECORD_MAX];
        unsigned long           unknown_events;
        struct rb_root          hists;
index 21b9216..fa96831 100644 (file)
@@ -79,8 +79,8 @@ int thread__comm_len(struct thread *self)
        return self->comm_len;
 }
 
-static size_t __map_groups__fprintf_maps(struct map_groups *self,
-                                        enum map_type type, FILE *fp)
+size_t __map_groups__fprintf_maps(struct map_groups *self,
+                                 enum map_type type, FILE *fp)
 {
        size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
        struct rb_node *nd;
@@ -89,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self,
                struct map *pos = rb_entry(nd, struct map, rb_node);
                printed += fprintf(fp, "Map:");
                printed += map__fprintf(pos, fp);
-               if (verbose > 1) {
+               if (verbose > 2) {
                        printed += dso__fprintf(pos->dso, type, fp);
                        printed += fprintf(fp, "--\n");
                }
@@ -183,8 +183,8 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
        return th;
 }
 
-static void map_groups__remove_overlappings(struct map_groups *self,
-                                           struct map *map)
+static int map_groups__fixup_overlappings(struct map_groups *self,
+                                         struct map *map)
 {
        struct rb_root *root = &self->maps[map->type];
        struct rb_node *next = rb_first(root);
@@ -209,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self,
                 * list.
                 */
                list_add_tail(&pos->node, &self->removed_maps[map->type]);
+               /*
+                * Now check if we need to create new maps for areas not
+                * overlapped by the new map:
+                */
+               if (map->start > pos->start) {
+                       struct map *before = map__clone(pos);
+
+                       if (before == NULL)
+                               return -ENOMEM;
+
+                       before->end = map->start - 1;
+                       map_groups__insert(self, before);
+                       if (verbose >= 2)
+                               map__fprintf(before, stderr);
+               }
+
+               if (map->end < pos->end) {
+                       struct map *after = map__clone(pos);
+
+                       if (after == NULL)
+                               return -ENOMEM;
+
+                       after->start = map->end + 1;
+                       map_groups__insert(self, after);
+                       if (verbose >= 2)
+                               map__fprintf(after, stderr);
+               }
        }
+
+       return 0;
 }
 
 void maps__insert(struct rb_root *maps, struct map *map)
@@ -254,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
 
 void thread__insert_map(struct thread *self, struct map *map)
 {
-       map_groups__remove_overlappings(&self->mg, map);
+       map_groups__fixup_overlappings(&self->mg, map);
        map_groups__insert(&self->mg, map);
 }
 
index 0a28f39..dcf7030 100644 (file)
@@ -10,6 +10,9 @@ struct map_groups {
        struct list_head        removed_maps[MAP__NR_TYPES];
 };
 
+size_t __map_groups__fprintf_maps(struct map_groups *self,
+                                 enum map_type type, FILE *fp);
+
 struct thread {
        struct rb_node          rb_node;
        struct map_groups       mg;